3

我在我的android應用程序中實現備份/恢復系統。恢復SQLite數據庫文件

自動備份每隔幾分鐘發生一次。 我試圖從我的SD卡恢復我的數據庫備份文件,我的應用程序被卸載後,然後再次安裝。

備份工作,但這裏的問題:
每當用戶再裝我的應用程序,有沒有發現異常的文件,但是,如果用戶關閉應用程序,然後再次打開它,恢復就好了。不知何故,應用程序第一次啓動時恢復面臨問題。

還原必須在第一次啓動時發生。

備註: backupExists函數返回true。

@Override 
public void onCreate(final Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    if(backUpExists()){ 

     restoreDB(); 
     } 
} 
    private boolean backUpExists() 
    { 
    try{ 
     File sd = Environment.getExternalStorageDirectory(); 
     if (sd.canRead()){ 
      String backupDBPath = "myDB"; 
      File backupedDB = new File(sd, backupDBPath); 
      if(backupedDB.exists()){ 
       return true; 
      } 
     } 
    } catch(Exception ex) { 
     Toast.makeText(getBaseContext(), ex.toString(), Toast.LENGTH_LONG).show(); 
    } 
     return false; 
    } 
    private void restoreDB() 
    { 
    try{ 
     File sd = Environment.getExternalStorageDirectory(); 
     File data = Environment.getDataDirectory(); 

     if (sd.canWrite()) { 
      String restroredDBPath = "//data//myPackage//databases//myDB"; 
      String backupDBPath = "myDB"; 
      File restoredDB = new File(data, restroredDBPath); 
      File backupedDB = new File(sd, backupDBPath); 
       FileChannel src = new FileInputStream(backupedDB).getChannel(); 
       FileChannel dst = new FileOutputStream(restoredDB).getChannel(); 
       dst.transferFrom(src, 0, src.size()); 
       src.close(); 
       dst.close(); 
       Toast.makeText(getBaseContext(), restoredDB.toString(), Toast.LENGTH_LONG).show(); 

     } 
    } catch (Exception e) { 

     Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show(); 
    } 
    } 

回溯

09-09 22:49:50.931: I/Database(23206): sqlite returned: error code = 26, msg = statement aborts at 14: [SELECT COUNT(*) FROM Photos WHERE AlbumId=0] file is encrypted or is not a database 
09-09 22:49:50.931: D/AndroidRuntime(23206): Shutting down VM 
09-09 22:49:50.931: W/dalvikvm(23206): threadid=1: thread exiting with uncaught exception (group=0x4151c700) 
09-09 22:49:50.931: E/AndroidRuntime(23206): FATAL EXCEPTION: main 
09-09 22:49:50.931: E/AndroidRuntime(23206): net.sqlcipher.database.SQLiteException: file is encrypted or is not a database 
09-09 22:49:50.931: E/AndroidRuntime(23206): at  net.sqlcipher.database.SQLiteQuery.native_fill_window(Native Method) 
09-09 22:49:50.931: E/AndroidRuntime(23206): at net.sqlcipher.database.SQLiteQuery.fillWindow(SQLiteQuery.java:73) 
09-09 22:49:50.931: E/AndroidRuntime(23206): at net.sqlcipher.database.SQLiteCursor.fillWindow(SQLiteCursor.java:290) 
[snipped] 
+0

,準確哪裏異常發生的呢?刪除'try' /'catch'以獲得正確的堆棧跟蹤。 –

+0

當我嘗試使用恢復的數據庫進行查詢時,出現「文件已加密或不是數據庫」異常。以下是完整的堆棧跟蹤:http://pastebin.com/j4tQU26K – idish

+0

@CL。忘了標記:) – idish

回答

14

請使用此代碼,它可以幫助你......我也做了同樣用這種方式

對於備份

try { 
    File sd = Environment.getExternalStorageDirectory(); 
    File data = Environment.getDataDirectory(); 

    if (sd.canWrite()) { 
     String currentDBPath = "//data/package name/databases/database_name"; 
     String backupDBPath = "database_name"; 
     File currentDB = new File(data, currentDBPath); 
     File backupDB = new File(sd, backupDBPath); 

     if (currentDB.exists()) { 
      FileChannel src = new FileInputStream(currentDB).getChannel(); 
      FileChannel dst = new FileOutputStream(backupDB).getChannel(); 
      dst.transferFrom(src, 0, src.size()); 
      src.close(); 
      dst.close(); 
      Toast.makeText(getApplicationContext(), "Backup is successful to SD card", Toast.LENGTH_SHORT).show(); 
     } 
    } 
} catch (Exception e) { 
} 

對於恢復

try { 
    File sd = Environment.getExternalStorageDirectory(); 
    File data = Environment.getDataDirectory(); 

    if (sd.canWrite()) { 
    String currentDBPath = "//data/package name/databases/database_name"; 
     String backupDBPath = "database_name"; 
     File currentDB = new File(data, currentDBPath); 
     File backupDB = new File(sd, backupDBPath); 

     if (currentDB.exists()) { 
      FileChannel src = new FileInputStream(backupDB).getChannel(); 
      FileChannel dst = new FileOutputStream(currentDB).getChannel(); 
      dst.transferFrom(src, 0, src.size()); 
      src.close(); 
      dst.close(); 
      Toast.makeText(getApplicationContext(), "Database Restored successfully", Toast.LENGTH_SHORT).show(); 
     } 
    } 
} catch (Exception e) { 
} 

兩者之間的一個小dfference u能在filechannel裏面看看情況。

+0

你的回答並沒有解決我的問題,但它讓我再次看到恢復操作之前真正發生的事情。我發現我正在使用新的數據庫功能,因此導致了所有問題。謝謝。 – idish

0

我感覺到的問題是讀取已存在的db文件。你實際上並沒有閱讀它,代碼只是在每次安裝應用程序時創建一個新代碼。你必須給你指的是爲了在你getExternalEvironment函數讀取它的數據庫文件的確切名稱..

+0

Ehm,問題已經解決,解決方案不是關於指定的代碼,但還有另一個問題。看看上面的答案中的評論,謝謝:) – idish

3
try 
{ 
    String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); 
    String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/CALC/Backup"; 
    //final 
    String inFileName = path+"/Calc_backup :"+date; 
    File dbFile = new File(inFileName); 
    FileInputStream fis = new FileInputStream(dbFile); 


    /*File dir = new File(path); 
    if(!dir.exists()) 
     dir.mkdirs();*/ 
    //Toast.makeText(getActivity(), "directory created @"+dir.getPath(), 2).show(); 

    // String outFileName = Environment.getExternalStorageDirectory()+"Calac/hems.txt"; 

    //String outFileName = path+"/"+date; 
    String outFileName = "/data/data/com.special.ResideMenuDemo/databases/Calq"; 

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

    // Transfer bytes from the inputfile to the outputfile 
    byte[] buffer = new byte[1024]; 
    int length; 

    while ((length = fis.read(buffer))>0) 
    { 
     output.write(buffer, 0, length); 
    } 

    Toast.makeText(getActivity(), "Restore Successfully", 2).show(); 
    // Close the streams 
    output.flush(); 
    output.close(); 
    fis.close(); 

} 
catch(Exception e) 
{ 
    e.printStackTrace(); 
}