[안드로이드] 엑셀 (Excel) 파일의 데이터를 데이터베이스에 넣기

2011.06.08 10:56

 

 

 

<목표> 

 

[안드로이드] 엑셀 파일의 데이터를 데이터베이스에 넣기

 

 오늘은 엑셀 파일의 데이터를 데이터베이스에 넣는 방법을 소개하고자 합니다. 유머나 명언 등을 서비스하고자 할 때는 기존의 데이터를 안드로이드의 데이터베이스에 넣는 작업이 필요합니다. 소스 자체에 데이터파일을 넣어 처음 시작 시에 데이터를 읽어 넣어주면 안드로이드 데이터베이스에 넣을 수 있습니다. 그 중 가장 쉽고 편리하고, 간단한 파일이 엑셀 (Excel) 파일이 아닐까 합니다. 아무래도 데이터형의 자료를 넣을 때는 편하니까 말이죠.

 

 간략히 방법을 설명해드리자면, 첫 번째로 안드로이드 프로젝트의 assets 폴더에 엑셀 파일을 넣습니다. 두번 째로 엑셀 파일을 읽어올 수 있는 라이브러리를 추가합니다. 그리고 마지막으로 해당 라이브러리를 이용하여 엑셀 파일을 읽어온 뒤에, 안드로이드 데이터베이스에 데이터를 넣어주면 됩니다. 의외로 간단하게 데이터를 넣을 수 있습니다.

 

 처음에는 SQLite Manager를 이용하여 .db 파일을 만들고, 그것을 안드로이드 데이터베이스에 직접 복사하여 넣는 방법을 썼었습니다. 하지만 굳이 중간의 복잡한 절차 없이 엑셀 파일로 간단히 하는 방법도 괜찮다는 생각에 위의 방법으로 시도해보았습니다. 생각보다 너무 간단해서 .db 파일을 만들면서 했던 고생이 아깝게 느껴졌을 정도였습니다.

 

그럼 차근 차근 알아보겠습니다.

   

   

  STEP 1 DBAdpater 생성하기 

 

 데이터 베이스를 편리하게 접근하는 DBAdapter가 필요합니다. 여기서는 예전에 포스팅하였던 [안드로이드] SQLite데이터베이스 이용하기의 NotesDbAdapter를 사용하겠습니다.

 

 

  STEP 2 엑셀 파일 추가하기 

 

 데이터가 저장되어 있는 엑셀 파일을 안드로이드 프로젝트의 assets 폴더에 넣습니다. 초기에 안드로이드 프로젝트 생성시 자동적으로 assets 폴더가 생성되어 있습니다. 혹시 없으신 분들은 폴더를 추가하시면 됩니다. 여기에서는 notes.xls 파일을 추가하였습니다.

 

 

  STEP 3 라이브러리 추가히기 

 

 엑셀에 접근하기 위해서 라이브러리가 필요합니다.  http://www.andykhan.com/jexcelapi/download.html 에서 JExcelApi 의 최신 버전을 받습니다. 압축을 풀어 jxl.jar 파일을 안드로이드 프로젝트에 추가하여 줍니다. 저는 lib라는 폴더를 생성하여 추가하여 넣었습니다. Jxl.jar에서 마우스 오른쪽으로 클릭하시고, Build Path, 그리고 Add to Build Path를 클릭하시면 라이브러리가 추가됩니다. JExcelApi 라이브러리에 대해 더 자세히 알고 싶으시다면, 링크를 따라가세요.

 

 

  STEP 4 데이터 접근 코드 

 

 이제 데이터에 직접 접근해보겠습니다.

 

package com.pulsewings.exceltodatabase;

import java.io.InputStream;
import jxl.Sheet;
import jxl.Workbook;
import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {

	private NotesDbAdapter dbAdapter;

	private static final String TAG = "NotesDbAdapter";

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		Log.d(TAG, "DatabaseTest :: onCreate()");
		this.dbAdapter = new NotesDbAdapter(this);

		copyExcelDataToDatabase();

		Button bt = (Button) findViewById(R.id.addButton);
		bt.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				String title = "러키";
				String body = "해피";

				dbAdapter.open();
				dbAdapter.createNote(title, body);
				dbAdapter.close();

				TextView tv = (TextView) findViewById(R.id.message);
				tv.setText(title + ", " + body + "를 추가하였습니다.");
			}
		});

		Button bt1 = (Button) findViewById(R.id.loadButton);
		bt1.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				dbAdapter.open();
				Cursor result = dbAdapter.fetchAllNotes();
				result.moveToFirst();
				String resultStr = "";
				while (!result.isAfterLast()) {
					String title = result.getString(1);
					String body = result.getString(2);
					resultStr += title + ", " + body + "\n";
					result.moveToNext();
				}

				TextView tv = (TextView) findViewById(R.id.message);
				tv.setText(resultStr);
				result.close();
				dbAdapter.close();
			}
		});
	}

	private void copyExcelDataToDatabase() {
		Log.w("ExcelToDatabase", "copyExcelDataToDatabase()");

		Workbook workbook = null;
		Sheet sheet = null;

		try {
			InputStream is = getBaseContext().getResources().getAssets().open("notes.xlsx");
			workbook = Workbook.getWorkbook(is);

			if (workbook != null) {
				sheet = workbook.getSheet(0);

				if (sheet != null) {

					int nMaxColumn = 2;
					int nRowStartIndex = 0;
					int nRowEndIndex = sheet.getColumn(nMaxColumn - 1).length - 1;
					int nColumnStartIndex = 0;
					int nColumnEndIndex = sheet.getRow(2).length - 1;

					dbAdapter.open();
					for (int nRow = nRowStartIndex; nRow <= nRowEndIndex; nRow++) {
						String title = sheet.getCell(nColumnStartIndex, nRow).getContents();
						String body = sheet.getCell(nColumnStartIndex + 1, nRow).getContents();
						dbAdapter.createNote(title, body);
					}
					dbAdapter.close();
				} else {
					System.out.println("Sheet is null!!");
				}
			} else {
				System.out.println("WorkBook is null!!");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (workbook != null) {
				workbook.close();
			}
		}
	}
}

   

 두 개의 버튼은 데이터베이스가 제대로 들어갔는지 확인하는 기능을 수행합니다. 첫번째 버튼은 임의로 데이터를만들어 데이터베이스에 넣고, 나머지 한개는 현재 데이터베이스에 들어있는 데이터를 모두 불러와 출력하는 역할을 합니다. 엑셀 파일을 접근하기 위한 핵심 함수는 copyExcelDataToDatabase() 부분입니다.

 

InputStream is = getBaseContext().getResources().getAssets().open("notes.xls");

 

 위의 한줄이 핵심 코드입니다. Assets 폴더에 있는 엑셀 파일을 가져와 JExcelApi에 적용시키기 위한 방법입니다. InputStream을 이용하여, JExcelApi의 Workbook에 넣어 줍니다. 나머지 소스 부분은 행과 열을 지정해줘서 해당 부분에 있는 데이터를 가져오는 부분입니다. 조금 더 구체적인 JExcelApi를 사용하시려면, 튜토리얼을 참고하세요.

 

 

  STEP 5 Xml Code

 

 Xml코드에는 테스트를 위해 TextView 하나와 Button이 두 개 있습니다.  

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="<://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/message"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

    <Button
        android:id="@+id/loadButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:lines="2"
        android:text="데이터베이스 불러오기" />

    <Button
        android:id="@+id/addButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:lines="2"
        android:text="데이터베이스 추가" />

</LinearLayout>

 

 

  STEP 6 AndroidManifest.xml Code

 

 데이터베이스를 이용하기 위해서 AndroidManifest.xml 코드 수정은 필요하지 않습니다.

 

 

 

<마무리> 엑셀 파일의 데이터를 데이터베이스에 넣기

 

 데이터베이스화된 데이터를 안드로이드에서 이용하고자 할 때, 데이터를 안드로이드 데이터베이스로 넣는 과정이 필요합니다. 가장 간단한 방법 중 하나가 엑셀 파일의 데이터를 넣는 방법이 아닐까합니다. 엑셀은 데이터를 데이터베이스화 하기 쉽게 되어 있어, 스프레드 시트로서의 역할을 충분히 하고 있다고 볼 수 있습니다. 그렇기 때문에 쉽게 데이터베이스화할 수 있으며, 관리하기도 쉬운 장점이 있습니다. 이러한 엑셀 파일의 데이터베이스를 안드로이드에서 이용하고자 하는 방법을 찾다가 JExcelApi 라이브러리를 알게 되었습니다. 이 라이브러리를 이용하면 손쉽게 엑셀 파일을 자바 환경에서 접근할 수가 있습니다. Assets 폴더에 엑셀 파일을 넣고, JExcelApi라이브러리를 이용하여, 데이터에 접근하여, 안드로이드 데이터베이스에 데이터를 넣을 수 있었습니다.

 

 

 

[ 참고자료 ]  

 

 

 


Posted by 
맥박맥박의 개발 일지

 

  • 2013년 7월 24일 본문 업데이트하였습니다.

 

맥박 안드로이드 , , , , , , , ,

  1. Blog Icon
    Haam

    좋은정보 감사드려요!! 정말 멋진 공간!!

  2. 감사합니닷!

  3. 저는 왜 엑셀과 연동이 안될까요 ㅠㅠ

  4. 만들고 있던 소스가 여기 다 있네요 ㅋㅋ
    감탄하고 갑니다.
    좋은 자료 감사합니다.

  5. Blog Icon
    프리미어

    내용도 좋지만 포스트 형식 정말 맘에 드네요.
    감사합니다.

  6. Blog Icon
    nill

    감사합니다.

  7. Blog Icon
    byul

    감사합니다^^
    저는 엑셀과 연동이 되지 않고
    Unfortunately, <앱이름> has stopped가 뜹니다.
    왜 그럴까요?? ㅠ

  8. Blog Icon
    rara

    오 잘되네용 ㅎㅎ 이걸 응용해서 다른것도 만들어봐야겟네용 ^^

  9. Blog Icon
    정윤

    이렇게하면 데이터수정시 디비파일이아닌 엑셀파일안에 데이터가저장되나요??

  10. 엑셀 데이터랑은 상관없습니다.
    안드로이드 내의 데이터베이스에 저장이 된답니다~!

  11. Blog Icon
    초보로이드

    동일하게 파일을 작성해서 만들어서 계속 수행을 할려고 하는데, 아래와 같은 에러가 발생하면서 앱이 켜지자마자 '중단되었습니다'라고 나오며 종료되고 있습니다.
    인터넷을 찾아봐서 하라는데로도 해봣는데, 변함이 없네요ㅠㅠ 제발 도와주시면 감사하겠습니다. 꾸벅꾸벅

    08-12 08:16:34.749: I/dalvikvm(608): threadid=3: reacting to signal 3
    08-12 08:16:34.879: I/dalvikvm(608): Wrote stack traces to '/data/anr/traces.txt'
    08-12 08:16:34.890: D/AndroidRuntime(608): Shutting down VM
    08-12 08:16:34.890: W/dalvikvm(608): threadid=1: thread exiting with uncaught exception (group=0x409c01f8)
    08-12 08:16:34.919: E/AndroidRuntime(608): FATAL EXCEPTION: main
    08-12 08:16:34.919: E/AndroidRuntime(608): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.testing/com.example.testing.DatabaseTestActivity}: java.lang.ClassNotFoundException: com.example.testing.DatabaseTestActivity
    08-12 08:16:34.919: E/AndroidRuntime(608): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1880)
    08-12 08:16:34.919: E/AndroidRuntime(608): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
    08-12 08:16:34.919: E/AndroidRuntime(608): at android.app.ActivityThread.access$600(ActivityThread.java:123)
    08-12 08:16:34.919: E/AndroidRuntime(608): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
    08-12 08:16:34.919: E/AndroidRuntime(608): at android.os.Handler.dispatchMessage(Handler.java:99)
    08-12 08:16:34.919: E/AndroidRuntime(608): at android.os.Looper.loop(Looper.java:137)
    08-12 08:16:34.919: E/AndroidRuntime(608): at android.app.ActivityThread.main(ActivityThread.java:4424)
    08-12 08:16:34.919: E/AndroidRuntime(608): at java.lang.reflect.Method.invokeNative(Native Method)
    08-12 08:16:34.919: E/AndroidRuntime(608): at java.lang.reflect.Method.invoke(Method.java:511)
    08-12 08:16:34.919: E/AndroidRuntime(608): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
    08-12 08:16:34.919: E/AndroidRuntime(608): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
    08-12 08:16:34.919: E/AndroidRuntime(608): at dalvik.system.NativeStart.main(Native Method)
    08-12 08:16:34.919: E/AndroidRuntime(608): Caused by: java.lang.ClassNotFoundException: com.example.testing.DatabaseTestActivity
    08-12 08:16:34.919: E/AndroidRuntime(608): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:61)
    08-12 08:16:34.919: E/AndroidRuntime(608): at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
    08-12 08:16:34.919: E/AndroidRuntime(608): at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
    08-12 08:16:34.919: E/AndroidRuntime(608): at android.app.Instrumentation.newActivity(Instrumentation.java:1023)
    08-12 08:16:34.919: E/AndroidRuntime(608): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1871)
    08-12 08:16:34.919: E/AndroidRuntime(608): ... 11 more
    08-12 08:16:35.251: I/dalvikvm(608): threadid=3: reacting to signal 3
    08-12 08:16:35.259: I/dalvikvm(608): Wrote stack traces to '/data/anr/traces.txt'
    08-12 08:16:35.509: I/dalvikvm(608): threadid=3: reacting to signal 3
    08-12 08:16:35.519: I/dalvikvm(608): Wrote stack traces to '/data/anr/traces.txt'

  12. java.lang.ClassNotFoundException: com.example.testing.DatabaseTestActivity 라는 에러 메시지로 보아,
    엑티비티를 찾을 수 없는 것이 문제인 것 같습니다. AndroidManifest.xml 파일에 DatabaseTestActivity 를 추가해보세요.
    '해당 엑티비티를 사용한다' 라는 선언이 필요합니다.

  13. Blog Icon
    Kcoder

    09-17 11:59:00.569: E/AndroidRuntime(12425): FATAL EXCEPTION: main
    09-17 11:59:00.569: E/AndroidRuntime(12425): java.lang.NoClassDefFoundError: jxl.Workbook
    09-17 11:59:00.569: E/AndroidRuntime(12425): at com.example.ablevoca.MainActivity.copyExcelDataToDatabase(MainActivity.java:78)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at com.example.ablevoca.MainActivity.onCreate(MainActivity.java:28)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at android.app.Activity.performCreate(Activity.java:5206)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2074)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2135)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at android.app.ActivityThread.access$700(ActivityThread.java:140)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at android.os.Handler.dispatchMessage(Handler.java:99)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at android.os.Looper.loop(Looper.java:137)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at android.app.ActivityThread.main(ActivityThread.java:4921)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at java.lang.reflect.Method.invokeNative(Native Method)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at java.lang.reflect.Method.invoke(Method.java:511)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
    09-17 11:59:00.569: E/AndroidRuntime(12425): at dalvik.system.NativeStart.main(Native Method)

    이런 에러가 계속 뜨는데 잡지를 못하겟어요
    라이브러리 추가 문제인듯 한데.. 위에 나온데로 했는데 무엇이 문제인지 알려주실수 있나요 ?

  14. Blog Icon
    열공로이드

    안녕하세요! 블로거님께 많은 도움을 받고 있는 학생입니다^^
    다름이 아니라 현재 말씀하신대로 해서 실행시키면 에러없이 정상적으로 작동이 되기는 합니다만,
    러키/해피만 계속 추가/불러오기 되고, 엑셀 파일은 불러오기가 되지 않습니다..ㅠㅠ
    정확하게 설명드리면

    앱 실행 - 데이터 불러오기/추가하기 두 개의 버튼
    - 불러오기 클릭 시 러키/해피 출력
    - 추가하기 클릭 시 러키/해피 추가

    이런 상황인데, 이 코드의 목적이 엑셀 파일을 읽어오는 것인데, 무엇이 문제일까요??...
    답변 해주시면 정말 감사하겠습니다.

  15. Blog Icon
    테스트안드로이더

    코드 별 이상없이 잘 동작합니다. xls 파일을 못읽는 건 아마도 xls 파일 컬럼에 빈곳이 있거나 length가 잘못 계산되서 그런듯 보여요..컬럼 데이터가 최소 2개이상 필요하니 최소한 컬럼 2칸은 만드셔야 될 듯..
    전 1개 컬럼으로만 했더니 exception 나더군요.

  16. thanks for share!

  17. Blog Icon

    비밀댓글입니다