【问题标题】:Restoring SQLite DB file恢复 SQLite 数据库文件
【发布时间】:2013-09-05 11:44:00
【问题描述】:

我正在我的 Android 应用中实现备份/恢复系统。

每隔几分钟自动备份一次。 在我的应用程序被卸载然后重新安装后,我正在尝试从我的 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]

【问题讨论】:

  • 异常究竟发生在哪里?删除 try/catch 以获得正确的堆栈跟踪。
  • 当我尝试使用恢复的数据库进行查询时,出现“文件已加密或不是数据库”异常。这是完整的堆栈跟踪:pastebin.com/j4tQU26K
  • @CL。忘记标记了:)
  • 这段代码在哪个类?是否有可能某些代码已经尝试打开数据库文件?
  • @CL。是的,有可能。我正在使用单调 DatabaseHelper 类,该类在还原操作之前已经实例化。但是,我尝试再次加载数据库库,并将我的数据库实例设置为 null,这样它将重新创建一个新的 DatabaseHelper 对象。不过,我遇到了同样的例外情况。

标签: android sqlite android-sdcard database-backups database-restore


【解决方案1】:

请使用此代码,它可能会对您有所帮助...我已经用这种方式做了同样的事情

用于备份

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) {
}

你可以在 if 条件下的文件通道中看到两者之间的一点差异。

【讨论】:

  • 您的回答并没有解决我的问题,但它让我再次看到了还原操作之前真正发生的情况。我发现我正在使用新的数据库功能,所以导致了所有问题。谢谢。
  • 它有时不会在内部存储中复制数据库文件内容。如果我从设备中提取数据库,它显示为空白。有时确实如此。无法识别问题。
  • @Patriotic 可能是因为我在将近 5 年前发表这篇文章。所以在那之后谷歌为了数据安全做了很多改变。这可能是这种行为的问题。
【解决方案2】:
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();
}

【讨论】:

    【解决方案3】:

    我觉得问题在于读取已经存在的 db 文件。您实际上并没有阅读它,代码只是在每次安装应用程序时创建一个新代码。您必须提供您所指的 db 文件的确切名称,以便在 getExternalEvironment 函数中读取它。..

    【讨论】:

    • Ehm,问题已经解决了,解决的不是指定的代码,而是另一个问题。看看你上面答案中的评论,谢谢:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-28
    • 2021-11-08
    • 1970-01-01
    相关资源
    最近更新 更多