Room数据库导出至Download目录时出现FileNotFoundException异常如何解决
问题排查
- 路径重复拼接错误:
代码中Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)返回的路径本身已经包含/storage/emulated/0前缀,你将它作为第二个参数传入new File(sd, backupDBPath)和sd路径二次拼接,导致最终路径出现重复段,和异常返回的错误路径完全吻合。 - 未指定备份文件名:
你当前的backupDB指向的是Download目录本身,而不是具体的数据库备份文件,直接往目录写入文件流自然会触发找不到文件的错误。 - 文件拷贝偏移量错误:
dst.transferFrom(src, 1, src.size())中第二个参数是源文件起始偏移量填了1,会丢失数据库文件的第一个字节,导出后的数据库会损坏无法使用,需要改为0。 - 权限适配问题:
安卓6.0及以上版本需要动态申请WRITE_EXTERNAL_STORAGE权限;安卓10及以上版本如果适配分区存储,需要用MediaStore API写入公共Download目录,或者如果你的应用targetSdk<=28,可以在manifest的application节点添加android:requestLegacyExternalStorage="true"做临时适配。
修正后代码
private void exportDB() { try { File data = Environment.getDataDirectory(); String currentDBPath = "/data/" + getPackageName() + "/databases/" + SAMPLE_DB_NAME; // 直接获取Download目录,不需要再和sd路径重复拼接 File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); // 明确指定备份文件为Download目录下的对应数据库文件 File backupDB = new File(downloadDir, SAMPLE_DB_NAME); File currentDB = new File(data, currentDBPath); if (currentDB.exists()) { // 先判断Download目录是否存在,不存在则创建 if (!downloadDir.exists()) { downloadDir.mkdirs(); } FileChannel src = new FileInputStream(currentDB).getChannel(); FileChannel dst = new FileOutputStream(backupDB).getChannel(); // 偏移量改为0,完整拷贝全文件 dst.transferFrom(src, 0, src.size()); src.close(); dst.close(); Toast.makeText(MainActivity.this, "数据库导出成功", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(MainActivity.this, "源数据库文件不存在", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { Log.e("MYAPP", "exception", e); Toast.makeText(MainActivity.this, "导出失败:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } }
内容的提问来源于stack exchange,提问作者Muhammad Asad.
相关产品推荐
相关产品推荐

