Android 上 SQLite 数据库的简单导出和导入
Posted
技术标签:
【中文标题】Android 上 SQLite 数据库的简单导出和导入【英文标题】:Simple export and import of a SQLite database on Android 【发布时间】: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
浏览器中查看原始数据库文件,它看起来很好。
【问题讨论】:
【参考方案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();
【讨论】:
以上是关于Android 上 SQLite 数据库的简单导出和导入的主要内容,如果未能解决你的问题,请参考以下文章
SQLite----Android Studio3.6.3 当前最新版本数据库查找与导出方法