晚上好,我正在开发一个Android应用程序,它具有SQLite数据库,我需要一种将数据库复制到设备外部存储的方法,可以在其中复制到另一台设备,以便将数据库导入到另一台设备。
例如:
假设应用程序调用“ example”,数据库位于“ /data/data/com.gnd.example/databases”文件夹中,并且名为data.db,则需要将其复制到“ example / backup”文件夹“,例如” / storage / emulated / 0 / example / backup”。这是第一部分。
第二部分是导入,应用程序应将文件从“ example / import”文件夹复制到文件夹“ /data/data/com.gnd.example/databases”
为此,我有两个按钮活动:btn_export和btn_import。
我已经依靠以下解决方案:
导入/导出到android sqlite数据库 在Android上轻松导出和导入SQLite数据库
我已经将其插入AndroidManifest中
如何请求用户许可?
我尝试使用示例中的代码进行复制
$count++
按钮如下所示:
private void backupDatabase () throws IOException {
String inFileName = "/data/data/com.gnd.example/databases/dados.db";
File dbFile = new File (inFileName);
FileInputStream fis = new FileInputStream (dbFile);
String outFileName = Environment.getExternalStorageDirectory () + "/ example / backup / data.db";
OutputStream output = new FileOutputStream (outFileName);
byte [] buffer = new byte [1024];
int length;
while ((length = fis.read (buffer))> 0) {
output.write (buffer, 0, length);
}
output.flush ();
output.close ();
fis.close ();
}
按下按钮时登录:
@Override
public void onClick (View view) {
try {
backupDatabase ();
} catch (IOException e1) {
e1.printStackTrace ();
}
});
答案 0 :(得分:2)
FileNotFoundException可能是由于目录 teste 不存在,可能是由于权限所致。
使用:-
private void backupDatabase () throws IOException {
String inFileName = "/data/data/com.gnd.example/databases/dados.db";
File dbFile = new File (inFileName);
FileInputStream fis = new FileInputStream (dbFile);
String outFileName = Environment.getExternalStorageDirectory () + "/ example / backup / data.db";
//<<<<<<<<<<< CODE ADDED >>>>>>>>>>
File os = new File(outFileName);
if (!os.getParentFile().exists()) {
os.getParentFile().mkdirs();
}
//<<<<<<<<<< END Of ADDED CODE >>>>>>>>>>
OutputStream output = new FileOutputStream(os); //<<<<<<<<<< CHANGED
byte [] buffer = new byte [1024];
int length;
while ((length = fis.read (buffer))> 0) {
output.write (buffer, 0, length);
}
output.flush ();
output.close ();
fis.close ();
}
如果目录不存在(假设权限正确),将创建目录
以下是可运行的应用程序
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="aso.so56843045backup">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
(对于较早的设备)class ExternalStoragePermissions {
public int API_VERSION = Build.VERSION.SDK_INT;
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
//Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
public static final String THISCLASS = ExternalStoragePermissions.class.getSimpleName();
private static final String LOGTAG = "SW_ESP";
public ExternalStoragePermissions() {}
// Note call this method
public static void verifyStoragePermissions(Activity activity) {
int permission = ActivityCompat.checkSelfPermission(
activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if(permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
}
public class DBHelper extends SQLiteOpenHelper {
public static final String DBNAME = "dados.db";
public static final int DBVERSION = 1;
public DBHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
this.getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
public class MainActivity extends AppCompatActivity {
DBHelper mDBHlpr;
Button mBackup;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBackup = this.findViewById(R.id.backup);
mBackup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDBHlpr.close();
try {
backupDatabase();
} catch (IOException e) {
e.printStackTrace();
}
}
});
ExternalStoragePermissions.verifyStoragePermissions(this);
mDBHlpr = new DBHelper(this);
}
private void backupDatabase () throws IOException {
FileInputStream fis = new FileInputStream (this.getDatabasePath("dados.db").getPath());
String outFileName = Environment.getExternalStorageDirectory () + "/example/backup/" + String.valueOf(System.currentTimeMillis()) + "data.db";
Log.d("OSFILEPATH",outFileName);
File os = new File(outFileName);
if (!os.getParentFile().exists()) {
os.getParentFile().mkdirs();
}
OutputStream output = new FileOutputStream(os);
byte [] buffer = new byte [1024];
int length;
while ((length = fis.read (buffer))> 0) {
output.write (buffer, 0, length);
}
output.flush ();
output.close ();
fis.close ();
}
}
在安装后首次运行时,将要求更高版本的设备提供许可(单击“允许”)。
备份已命名为带有时间戳,因此可以存在多个备份。
数据库已关闭,(这应与Android Pie +配合使用,默认情况下为WAL模式,关闭应清空(提交更改)-wal和-shm文件,从而无需备份其他文件)
答案 1 :(得分:2)
关于您的崩溃:
您尚未创建目录,至少没有通过代码创建目录。创建一个指向所需目录的File
对象,然后在该对象上调用mkdirs()
。
您可能没有持有WRITE_EXTERNAL_STORAGE
权限,包括在运行时请求它。参见https://developer.android.com/training/permissions/requesting。
这里的其他问题包括:
您将无法写入您请求的位置in Android Q (by default) and Android R (for all apps)。建议您写getExternalFilesDir()
(在Context
上)或使用Storage Access Framework。
您正在执行主应用程序线程上的磁盘I / O。这将导致您的UI在发生I / O时冻结。用户可能认为您的应用程序已损坏。解决问题的方法很多,尽管Jetpack的方法是使用ViewModel
和LiveData
。
您不打算通过MediaStore
为文件建立索引,因此用户将无法在其桌面文件管理器中看到它。使用MediaScannerConnection.scanFile()
为文件建立索引。
"/data/data/com.gnd.example/databases/dados.db"
是许多Android设备上的错误路径。永远不要硬编码路径。在getDatabasePath()
上使用Context
来获取数据库的路径。
This sample Java app显示了在文本编辑器而不是数据库备份解决方案的背景下完成了很多操作。
通常,我建议您将这个项目搁置一段时间,并阅读有关Android应用程序开发的最新书籍。我在这里提到的大多数问题都是与Android上不错的书有关的主题。