【问题标题】:Simple export and import of a SQLite database on AndroidAndroid 上 SQLite 数据库的简单导出和导入
【发布时间】:2011-09-26 07:43:48
【问题描述】:

我正在尝试实现一个简单的SQLite 导出/导入以进行备份。导出只是存储原始current.db 文件的副本。我想要导入的只是删除旧的current.db 文件并将imported.db 文件重命名为current.db。这可能吗?当我尝试此解决方案时,我收到以下错误:

06-30 13:33:38.831: ERROR/SQLiteOpenHelper(23570):
    android.database.sqlite.SQLiteDatabaseCorruptException: error code 11: database disk image is malformed

如果我在 SQLite 浏览器中查看原始数据库文件,它看起来很好。

【问题讨论】:

    标签: java android database sqlite


    【解决方案1】:

    我在我的一个应用程序的SQLiteOpenHelper 中使用此代码来导入数据库文件。

    编辑:我将FileUtils.copyFile() 方法粘贴到问题中。

    SQLiteOpenHelper

    public static String DB_FILEPATH = "/data/data/{package_name}/databases/database.db";
    
    /**
     * Copies the database file at the specified location over the current
     * internal application database.
     * */
    public boolean importDatabase(String dbPath) throws IOException {
    
        // Close the SQLiteOpenHelper so it will commit the created empty
        // database to internal storage.
        close();
        File newDb = new File(dbPath);
        File oldDb = new File(DB_FILEPATH);
        if (newDb.exists()) {
            FileUtils.copyFile(new FileInputStream(newDb), new FileOutputStream(oldDb));
            // Access the copied database so SQLiteHelper will cache it and mark
            // it as created.
            getWritableDatabase().close();
            return true;
        }
        return false;
    }
    

    FileUtils

    public class FileUtils {
        /**
         * Creates the specified <code>toFile</code> as a byte for byte copy of the
         * <code>fromFile</code>. If <code>toFile</code> already exists, then it
         * will be replaced with a copy of <code>fromFile</code>. The name and path
         * of <code>toFile</code> will be that of <code>toFile</code>.<br/>
         * <br/>
         * <i> Note: <code>fromFile</code> and <code>toFile</code> will be closed by
         * this function.</i>
         * 
         * @param fromFile
         *            - FileInputStream for the file to copy from.
         * @param toFile
         *            - FileInputStream for the file to copy to.
         */
        public static void copyFile(FileInputStream fromFile, FileOutputStream toFile) throws IOException {
            FileChannel fromChannel = null;
            FileChannel toChannel = null;
            try {
                fromChannel = fromFile.getChannel();
                toChannel = toFile.getChannel();
                fromChannel.transferTo(0, fromChannel.size(), toChannel);
            } finally {
                try {
                    if (fromChannel != null) {
                        fromChannel.close();
                    }
                } finally {
                    if (toChannel != null) {
                        toChannel.close();
                    }
                }
            }
        }
    }
    

    如有必要,不要忘记删除旧的数据库文件。

    【讨论】:

    • 记得给你喜欢的答案投票,帮助社区知道哪些是好的,哪些是垃圾。
    • Austyn 的上述答案也对我有用。有一点需要注意,这里没有说明,使用 String path = Environment.getExternalStorageDirectory().toString() + "/{appName}/";设置 SD 卡上的写入路径。
    • 这是有道理的。这是一些很好的建议。我实际上是在自己的应用程序中执行此操作,但在此演示代码中仅包含一个字符串文字作为占位符。
    • @AustynMahoney:这可以在非 root 设备上使用吗?
    • 数据库路径:context.getDatabasePath("db_filename")
    【解决方案2】:

    这是将数据库导出到名为备份文件夹的文件夹的简单方法,您可以根据需要对其进行命名,以及从同一文件夹中导入数据库的简单方法a

        public class ExportImportDB extends Activity {
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                // TODO Auto-generated method stub
                super.onCreate(savedInstanceState);
    //creating a new folder for the database to be backuped to
                File direct = new File(Environment.getExternalStorageDirectory() + "/Exam Creator");
    
                   if(!direct.exists())
                    {
                        if(direct.mkdir()) 
                          {
                           //directory is created;
                          }
    
                    }
                exportDB();
                importDB();
    
            }
        //importing database
            private void importDB() {
                // TODO Auto-generated method stub
    
                try {
                    File sd = Environment.getExternalStorageDirectory();
                    File data  = Environment.getDataDirectory();
    
                    if (sd.canWrite()) {
                        String  currentDBPath= "//data//" + "PackageName"
                                + "//databases//" + "DatabaseName";
                        String backupDBPath  = "/BackupFolder/DatabaseName";
                        File  backupDB= new File(data, currentDBPath);
                        File currentDB  = new File(sd, backupDBPath);
    
                        FileChannel src = new FileInputStream(currentDB).getChannel();
                        FileChannel dst = new FileOutputStream(backupDB).getChannel();
                        dst.transferFrom(src, 0, src.size());
                        src.close();
                        dst.close();
                        Toast.makeText(getBaseContext(), backupDB.toString(),
                                Toast.LENGTH_LONG).show();
    
                    }
                } catch (Exception e) {
    
                    Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG)
                            .show();
    
                }
            }
        //exporting database 
            private void exportDB() {
                // TODO Auto-generated method stub
    
                try {
                    File sd = Environment.getExternalStorageDirectory();
                    File data = Environment.getDataDirectory();
    
                    if (sd.canWrite()) {
                        String  currentDBPath= "//data//" + "PackageName"
                                + "//databases//" + "DatabaseName";
                        String backupDBPath  = "/BackupFolder/DatabaseName";
                        File currentDB = new File(data, currentDBPath);
                        File backupDB = new File(sd, backupDBPath);
    
                        FileChannel src = new FileInputStream(currentDB).getChannel();
                        FileChannel dst = new FileOutputStream(backupDB).getChannel();
                        dst.transferFrom(src, 0, src.size());
                        src.close();
                        dst.close();
                        Toast.makeText(getBaseContext(), backupDB.toString(),
                                Toast.LENGTH_LONG).show();
    
                    }
                } catch (Exception e) {
    
                    Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG)
                            .show();
    
                }
            }
    
        }
    

    不要忘记添加此权限以继续它

      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
        </uses-permission>
    

    享受

    【讨论】:

    • importDB 和 exportDB 过程不知何故完全相同?
    • 错误:如果仔细观察,'currentDB' 变量指的是 importDB 中的 data 文件夹文件,以及 exportDB 中的 sd 文件夹。
    • 还有一个问题,你如何通过点击android上的一个按钮来实现它。
    • 如果在复制过程中数据库文件发生变化会怎样?
    • 小心实现。在数据库导出期间的任何错误情况下都会出现内存泄漏。原因是两个流(FileInputStream 和 FileOutputStream)都没有在 finally 中关闭。
    【解决方案3】:

    导出 db 而不是 SQLITE 或 ROOM:

    首先,在 AndroidManifest.xml 文件中添加这个权限:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    

    其次,我们开始编写 db 函数:

    private void exportDB() {
        try {
            File dbFile = new File(this.getDatabasePath(DATABASE_NAME).getAbsolutePath());
            FileInputStream fis = new FileInputStream(dbFile);
    
            String outFileName = DirectoryName + File.separator +
                    DATABASE_NAME + ".db";
    
            // 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);
            }
            // Close the streams
            output.flush();
            output.close();
            fis.close();
    
    
        } catch (IOException e) {
            Log.e("dbBackup:", e.getMessage());
        }
    }
    

    每天创建文件夹,文件夹名称为当前日期:

    public void createBackup() {
    
        sharedPref = getSharedPreferences("dbBackUp", MODE_PRIVATE);
        editor = sharedPref.edit();
    
        String dt = sharedPref.getString("dt", new SimpleDateFormat("dd-MM-yy").format(new Date()));
    
        if (dt != new SimpleDateFormat("dd-MM-yy").format(new Date())) {
            editor.putString("dt", new SimpleDateFormat("dd-MM-yy").format(new Date()));
    
            editor.commit();
        }
    
        File folder = new File(Environment.getExternalStorageDirectory() + File.separator + "BackupDBs");
        boolean success = true;
        if (!folder.exists()) {
            success = folder.mkdirs();
        }
        if (success) {
    
            DirectoryName = folder.getPath() + File.separator + sharedPref.getString("dt", "");
            folder = new File(DirectoryName);
            if (!folder.exists()) {
                success = folder.mkdirs();
            }
            if (success) {
                exportDB();
            }
        } else {
            Toast.makeText(this, "Not create folder", Toast.LENGTH_SHORT).show();
        }
    
    }
    

    分配不带 .db 扩展名的 DATABASE_NAME,其数据类型为字符串

    【讨论】:

      【解决方案4】:

      如果你想在 kotlin 中使用它。并且完美运行

       private fun exportDbFile() {
      
          try {
      
              //Existing DB Path
              val DB_PATH = "/data/packagename/databases/mydb.db"
              val DATA_DIRECTORY = Environment.getDataDirectory()
              val INITIAL_DB_PATH = File(DATA_DIRECTORY, DB_PATH)
      
              //COPY DB PATH
              val EXTERNAL_DIRECTORY: File = Environment.getExternalStorageDirectory()
              val COPY_DB = "/mynewfolder/mydb.db"
              val COPY_DB_PATH = File(EXTERNAL_DIRECTORY, COPY_DB)
      
              File(COPY_DB_PATH.parent!!).mkdirs()
              val srcChannel = FileInputStream(INITIAL_DB_PATH).channel
      
              val dstChannel = FileOutputStream(COPY_DB_PATH).channel
              dstChannel.transferFrom(srcChannel,0,srcChannel.size())
              srcChannel.close()
              dstChannel.close()
      
          } catch (excep: Exception) {
              Toast.makeText(this,"ERROR IN COPY $excep",Toast.LENGTH_LONG).show()
              Log.e("FILECOPYERROR>>>>",excep.toString())
              excep.printStackTrace()
          }
      
      }
      

      【讨论】:

      • 它给我一个错误,找不到这样的文件或目录
      【解决方案5】:

      在 Android 上导入和导出 SQLite 数据库

      这是我将数据库导出到设备存储的功能

      private void exportDB(){
          String DatabaseName = "Sycrypter.db";
          File sd = Environment.getExternalStorageDirectory();
          File data = Environment.getDataDirectory();
          FileChannel source=null;
          FileChannel destination=null;
          String currentDBPath = "/data/"+ "com.synnlabz.sycryptr" +"/databases/"+DatabaseName ;
          String backupDBPath = SAMPLE_DB_NAME;
          File currentDB = new File(data, currentDBPath);
          File backupDB = new File(sd, backupDBPath);
          try {
              source = new FileInputStream(currentDB).getChannel();
              destination = new FileOutputStream(backupDB).getChannel();
              destination.transferFrom(source, 0, source.size());
              source.close();
              destination.close();
              Toast.makeText(this, "Your Database is Exported !!", Toast.LENGTH_LONG).show();
          } catch(IOException e) {
              e.printStackTrace();
          }
      }
      

      这是我将数据库从设备存储导入到 android 应用程序的功能

      private void importDB(){
          String dir=Environment.getExternalStorageDirectory().getAbsolutePath();
          File sd = new File(dir);
          File data = Environment.getDataDirectory();
          FileChannel source = null;
          FileChannel destination = null;
          String backupDBPath = "/data/com.synnlabz.sycryptr/databases/Sycrypter.db";
          String currentDBPath = "Sycrypter.db";
          File currentDB = new File(sd, currentDBPath);
          File backupDB = new File(data, backupDBPath);
      
          try {
              source = new FileInputStream(currentDB).getChannel();
              destination = new FileOutputStream(backupDB).getChannel();
              destination.transferFrom(source, 0, source.size());
              source.close();
              destination.close();
              Toast.makeText(this, "Your Database is Imported !!", Toast.LENGTH_SHORT).show();
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-05-08
        • 2019-11-12
        • 1970-01-01
        • 1970-01-01
        • 2021-10-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多