2014-09-23 2 views
0

이것은 Android에 내 첫 번째 응용 프로그램입니다. 이 문제에 대해 몇 가지 질문을했지만 아무도 나를위한 해결책이 없었습니다.장치에 복사 할 자산 폴더의 sqlite 파일을 열 수 없습니다.

fmdb.sqlite라는 자산 폴더에 데이터베이스가 있습니다. 내가 자산 폴더 (copyDataBase 방법)에 SQLite는 파일 스트림을 받아야 라인에 도착하면 http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/

, 나는 "java.io.FileNotFoundException 예외가 :이 링크에서 코드 예제를 사용 : fmdb.sqlite "를 참조하십시오.

아무도 내가 뭘 잘못하고 있다고 말할 수 있습니까? 여기 수업이 있습니다.

public class DatabaseOpener extends SQLiteOpenHelper { 

// If you change the database schema, you must increment the database version. 
public static final int DATABASE_VERSION = 1; 

//The Android's default system path of your application database. 
public static String DB_PATH; 

public static String DB_NAME = "fmdb.sqlite"; 

private SQLiteDatabase myDataBase; 

private final Context myContext; 



public DatabaseOpener(Context context) throws IOException { 
    super(context, DB_NAME, null, DATABASE_VERSION); 
    myContext = context; 
} 

/** 
* Check if the database already exists to avoid re-copying the file each time you open the application. 
* @return true if it exists, false if it doesn't 
*/ 
    private boolean checkDataBase(){ 

     SQLiteDatabase checkDB = null; 

     try{ 
     String myPath = DB_PATH; 
     checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); 

     }catch(SQLiteException e){ 

     //database does't exist yet. 

     } 

     if(checkDB != null){ 

     checkDB.close(); 

    } 

    return checkDB != null ? true : false; 
    } 

    /** 
    * Creates a empty database on the system and rewrites it with your own database. 
    * */ 
    public void createDataBase() throws IOException{ 

     boolean dbExist = checkDataBase(); 

     if(dbExist){ 
      //do nothing - database already exist 
      }else{ 

      //By calling this method and empty database will be created into the default system path 
      //of your application so we are gonna be able to overwrite that database with our database. 
      this.getReadableDatabase(); 

      try { 

      copyDataBase(); 

      } catch (IOException e) { 

      throw new Error("Error copying database"); 

      } 
     } 

    } 

    /** 
    * Copies your database from your local assets-folder to the just created empty database in the 
    * system folder, from where it can be accessed and handled. 
    * This is done by transfering bytestream. 
    * */ 
private void copyDataBase() throws IOException{ 

    //Open your local db as the input stream 
    InputStream myInput = myContext.getAssets().open(DB_NAME); 

    // Path to the just created empty db 
    String outFileName = DB_PATH; 

    //Open the empty db as the output stream 
    OutputStream myOutput = new FileOutputStream(outFileName); 

    //transfer bytes from the inputfile to the outputfile 
    byte[] buffer = new byte[1024]; 
    int length; 
    while ((length = myInput.read(buffer))>0){ 
    myOutput.write(buffer, 0, length); 
    } 

    //Close the streams 
    myOutput.flush(); 
    myOutput.close(); 
    myInput.close(); 

} 

public SQLiteDatabase openDataBase() throws SQLException{ 

    //Open the database 
    String myPath = DB_PATH;// + DB_NAME; 
    myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); 

    return myDataBase; 
} 

@Override 
public synchronized void close() { 

    if(myDataBase != null) 
    myDataBase.close(); 

    super.close(); 

} 



@Override 
public void onCreate(SQLiteDatabase db) { 
    // TODO Auto-generated method stub 

} 

@Override 
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
    // TODO Auto-generated method stub 

} 

}

편집 여기에 2 는 로그 캣입니다. 프로그램을 제거하고 다시 실행했습니다. 이제는 DB 파일을 작성하여 열어두면 도움이됩니다.

09-29 17:59:19.540: W/SQLiteAssetHelper(27063): copying database from assets... 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): Couldn't open fmdb.sqlite for writing (will try read-only): 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): com.readystatesoftware.sqliteasset.SQLiteAssetHelper$SQLiteAssetException: Missing databases/fmdb.sqlite file (or .zip, .gz archive) in assets, or target folder not writable 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at android.content.res.AssetManager.openAsset(Native Method) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at android.content.res.AssetManager.open(AssetManager.java:315) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at android.content.res.AssetManager.open(AssetManager.java:289) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at com.readystatesoftware.sqliteasset.SQLiteAssetHelper.copyDatabaseFromAssets(SQLiteAssetHelper.java:436) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at com.readystatesoftware.sqliteasset.SQLiteAssetHelper.createOrOpenDatabase(SQLiteAssetHelper.java:400) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at com.readystatesoftware.sqliteasset.SQLiteAssetHelper.getWritableDatabase(SQLiteAssetHelper.java:176) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at com.readystatesoftware.sqliteasset.SQLiteAssetHelper.getReadableDatabase(SQLiteAssetHelper.java:254) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at com.friendlymeter.dal.MyDatabase.getSample(MyDatabase.java:27) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at com.friendlymeter.app.MainActivity$2.onClick(MainActivity.java:105) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at android.view.View.performClick(View.java:4204) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at android.view.View$PerformClick.run(View.java:17355) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at android.os.Handler.handleCallback(Handler.java:725) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at android.os.Handler.dispatchMessage(Handler.java:92) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at android.os.Looper.loop(Looper.java:137) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at android.app.ActivityThread.main(ActivityThread.java:5041) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at java.lang.reflect.Method.invokeNative(Native Method) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at java.lang.reflect.Method.invoke(Method.java:511) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 09-29 17:59:19.689: E/SQLiteAssetHelper(27063): at dalvik.system.NativeStart.main(Native Method) 09-29 17:59:19.709: E/SQLiteLog(27063): (14) cannot open file at line 30176 of [00bb9c9ce4] 09-29 17:59:19.709: E/SQLiteLog(27063): (14) os_unix.c:30176: (2) open(/data/data/com.friendlymeter.app/databases/fmdb.sqlite) - 09-29 17:59:19.909: D/dalvikvm(27063): GC_CONCURRENT freed 130K, 9% free 2652K/2904K, paused 9ms+15ms, total 171ms 09-29 17:59:20.019: E/SQLiteDatabase(27063): Failed to open database '/data/data/com.friendlymeter.app/databases/fmdb.sqlite'. 09-29 17:59:20.019: E/SQLiteDatabase(27063): android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:804) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:789) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:669) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at com.readystatesoftware.sqliteasset.SQLiteAssetHelper.getReadableDatabase(SQLiteAssetHelper.java:264) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at com.friendlymeter.dal.MyDatabase.getSample(MyDatabase.java:27) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at com.friendlymeter.app.MainActivity$2.onClick(MainActivity.java:105) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.view.View.performClick(View.java:4204) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.view.View$PerformClick.run(View.java:17355) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.os.Handler.handleCallback(Handler.java:725) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.os.Handler.dispatchMessage(Handler.java:92) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.os.Looper.loop(Looper.java:137) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at android.app.ActivityThread.main(ActivityThread.java:5041) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at java.lang.reflect.Method.invokeNative(Native Method) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at java.lang.reflect.Method.invoke(Method.java:511) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 09-29 17:59:20.019: E/SQLiteDatabase(27063): at dalvik.system.NativeStart.main(Native Method) 
+3

하십시오 [사용'SQLiteAssetHelper'] (https://github.com/jgilfelt/android-sqlite-asset-helper)로 데이터베이스를 포장에 대한 자산. – CommonsWare

+0

DB_PATH는 항상 비어 있습니다. 이 코드는 어떻게 작동해야합니까? – greenapps

+0

@greenapps DB_PATH를 초기화하는 클래스 내에 정적 섹션이 있습니다 (코드에는 포함되어 있지 않습니다 ...) – amazingwolf

답변

2

나는 CommonsWare의 의견에 100 % 동의합니다. 가장 쉬운 방법은 SQLiteAssetHelper을 사용하는 것입니다. 나는 이것을 답으로 게시 할 것이지만 이것은 위의 링크에서 붙여 넣은 100 % 사본입니다. 이 라이브러리를 사용하려면 알아야 할 모든 것입니다.

SQLiteAssetHelper는 프레임 워크의 SQLiteOpenHelper 대신 사용할 수 있습니다. 해당 학급의 행동 및 라이프 사이클을 숙지하시기 바랍니다. 일반적 SQLiteOpenHelper를하는 것처럼

은 데이터베이스 이름 및 버전 번호와 함께 생성자를 제공 SQLiteAssetHelper 확장 :

public class MyDatabase extends SQLiteAssetHelper { 

    private static final String DATABASE_NAME = "northwind.db"; 
    private static final int DATABASE_VERSION = 1; 

    public MyDatabase(Context context) { 
     super(context, DATABASE_NAME, null, DATABASE_VERSION); 
    } 
} 

SQLiteAssetHelper 자산 파일 및 폴더 이름 지정 규칙에 의존한다. 애셋 폴더는 기본 gradle 프로젝트 구조를 사용하는 경우 프로젝트 루트 아래에 있거나 src/main 아래에 있습니다.

애셋 내부 데이터베이스 폴더 파일 이름이 코드에서 제공 한 데이터베이스 이름과 일치하는 데이터베이스 폴더 내의 SQLite 데이터베이스 (파일 확장명이있는 경우) 예를 들어 프로젝트는 다음을 포함합니다.

assets/databases/northwind.db 이 라이브러리의 이전 버전에서는 데이터베이스 자산을 ZIP 아카이브 내에서 압축해야했습니다. 이것은 더 이상 요구 사항은 아니지만 계속 지원됩니다. Gingerbread (API 10) 이하를 대상으로하는 응용 프로그램은 계속해서 압축 된 아카이브를 제공하여 패키징 프로세스 중에 대형 데이터베이스 파일이 손상되지 않도록해야합니다. Linux 친화적 인 GZIP 형식도 지원됩니다. 위의 예제를 사용한 명명 규칙은 다음과 같습니다.

ZIP : assets/databases/northwind.db.zip (단일 SQLite 데이터베이스 파일 만 아카이브 내의 유일한 파일이어야합니다) GZIP : assets/databases/northwind. db.gz 데이터베이스가 자산에서 추출되고 응용 프로그램의 개인 데이터 디렉토리에 복사됩니다. 데이터베이스 파일을 다른 저장소 (예 : 외부 저장소)에 저장하려면 대체 생성자를 사용하여 저장소 경로를 지정할 수 있습니다. 응용 프로그램이 데이터베이스에 액세스해야 할 때마다이 경로가 사용 가능하고 쓸 수 있는지 확인해야합니다.

super(context, DATABASE_NAME, context.getExternalFilesDir(null).getAbsolutePath(), null, DATABASE_VERSION); 

데이터베이스

는 사용을 위해 처음 호출 중 하나 getReadableDatabase() 또는 getWritableDatabase()를 사용할 수 있습니다.

적절하게 명명 된 파일을 제공하지 않으면 클래스에서 SQLiteAssetHelperException을 발생시킵니다.

onConfigure, onCreate 및 onDowngrade의 SQLiteOpenHelper 메서드는이 구현에서 지원되지 않으며 final로 선언되었습니다.

편집

도움 요청, 지금 주어진. 먼저 은 폴더 안에 databases 폴더를 넣고이되어야합니다. databases, 정확히 의 철자가 있어야하고 대소 문자를 구분하는이어야합니다. 바로이 곳에서 라이브러리가 데이터베이스를 찾습니다. 다음 이어야합니다. 을 libs 폴더에 넣으십시오. 이제 코드를 작성하십시오.

다음은 작동중인 샘플 코드입니다. 나는 마침내 그것이 내가 처음 게시 된 코드와 함께 작동하도록 있어요 - 당신이 날

+0

SQLiteAssetHelper를 확장 한 클래스를 만들고 데이터/data /.../ databases 폴더에 있습니다. 여기에 : public void testCreation() { \t SQLiteDatabase db = getReadableDatabase(); } 전화가 왔을 때 - 예외가 발생했습니다 : android.database.sqlite.SQLiteCantOpenDatabaseException : 알 수없는 오류 (코드 14) : 데이터베이스를 열 수 없습니다. 데이터베이스 파일을 에셋 폴더에 직접 놓은 다음 에셋/데이터베이스 폴더에 넣으려고했습니다. 여전히 운이 없습니다. 도움말 ... ... – amazingwolf

+0

@amazingwolf 편집 – Jawascript

+0

이 복사하고 관련 테이블 이름과 열을 넣어 다른 오류 (만세?) : 'android.database.sqlite.SQLiteCantOpenDatabaseException : 알 수없는 오류 (코드 14) : 데이터베이스를 열 수 없습니다 ' 지금은 검색 중입니다 - 내 데이터베이스가 sqlite 브라우저에서 열리므로 병합되지 않습니다. – amazingwolf

0

확인을 알려 다른 작업을해야하는 경우

public class MyDatabase extends SQLiteAssetHelper { 

    private static String DATABASE_NAME = "your_database_name.sqlite"; // must have file extension 
    private static int DATABASE_VERSION = 1; 

    public static final String SAMPLE_TABLE = "your_table_name"; 

    public static final String SAMPLE_COLUMN= "your_column_name"; 

    public MyDatabase(Context context) { 
     super(context, DATABASE_NAME, null, DATABASE_VERSION); 
    } 

    /** 
    * Returns a sample string. 
    * @return sample - a sample string from your database table 
    */ 
    public String getSample() { 
     SQLiteDatabase database = this.getReadableDatabase(); 
     String[] columnsArray = { SAMPLE_COLUMN }; 
     Cursor cursor = database.query(true, SAMPLE_TABLE, columnsArray, null, null, null, null, null, null); 
     if (cursor != null) { 
      cursor.moveToFirst(); 
     } 

     String sample = cursor.getString(cursor.getColumnIndex(SAMPLE_COLUMN)); 

     cursor.close(); 
     database.close(); 

     return sample; 
    } 
} 

그런 다음이

public void databaseTest() { 
    MyDatabase db = new MyDatabase(YourActivity.this); 
    String sample = db.getSample(); 
    Log.v("SAMPLE", sample); 
    db.close(); 
} 

같은 앱에서 호출. 이 솔루션은 SQLiteAssetHelper를 사용하지 않아도됩니다 (실제로 작성해야하는 코드의 양은 줄어 듭니다). 대단한 도움을 주신 @javascript에 감사드립니다. 내가 가지고있는 오래된 sqlite db를 가져 와서 그 응용 프로그램을 실행했습니다 - 그것을 읽을 때 예외가 없었습니다. 내 원본 파일이 모든 sqlite 관리 도구에서 열렸지 만 (손상되지 않도록), 새 데이터베이스 파일을 만들기로 결정했습니다.

코드와 응용 프로그램 데이터베이스를 테스트하는 데 사용한 이전 데이터베이스와 다른 점은 파일 확장명 (스키마 제외)입니다. 이전 데이터베이스 확장자는 ".db"였고 app 데이터베이스는 ".sqlite"였습니다. 그래서 나는 ".db"EXTENSION으로 새로운 데이터베이스를 만들었고 그 안에 모든 테이블을 만들었고 - voila - 에셋의 데이터베이스 폴더에있는 파일을 자산 폴더에서 복사하는 데 성공했습니다.

희망이 누군가가이 :) 정말 실망하고 있었다 도움이

관련 문제