试图在 Android 中复制 SQLite 数据库并得到“没有这样的文件或目录”

Posted

技术标签:

【中文标题】试图在 Android 中复制 SQLite 数据库并得到“没有这样的文件或目录”【英文标题】:Trying to copy SQLite database in Android and getting "No such file or directory" 【发布时间】:2018-06-26 19:15:02 【问题描述】:

我有一个数据库,我想将它复制到 SD 卡以保留备份,我找到了以下代码:

private void exportDB()
    File sd = Environment.getExternalStorageDirectory();
    File data = Environment.getDataDirectory();
    FileChannel source=null;
    FileChannel destination=null;
    String currentDBPath = "/data/"+ "com.example.myapp" +"/databases/"+"mydatabase";
    String backupDBPath = "/storage/extSdCard/mydatabase";
    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();
     catch(IOException e) 
        //e.printStackTrace();
        Toast.makeText(this, "Err:"+e, Toast.LENGTH_LONG).show();
    

正如我在标题中所写,当我尝试执行此操作时收到 No such file or directoryENOENT 错误。

显然数据库应该存储在那里。 我尝试将路径更改为一些不同的东西,但仍然没有... 我试过了:

"/data/"+ "com.example.myapp" +"/"+"mydatabase.db"

"//data//"+ "com.example.myapp" +"//databases//"+"mydatabase"

Edit1:也试过这个,也不起作用:

String currentDBPath = this.getDatabasePath("mydatabase").toString();

等等。没有任何效果,我也找不到以任何方式检查路径的方法。

我基本上已经建立了数据库,在其中插入了几行并具有一些基本功能,例如add()delete() 等。我错过了什么吗?我不知道我还能尝试什么。

以下是 logcat 对此的看法:

01-18 11:34:46.215 10337-10337/com.example.myapp D/DBPATH: 数据库路径是/data/data/com.example.myapp/databases/mydatabase.db

01-18 11:34:46.225 10337-10337/com.example.myapp W/System.err:java.io.FileNotFoundException:/data/data/com.example.myapp/databases/mydatabase.db:打开失败:ENOENT(没有这样的文件或目录)

01-18 11:34:46.235 10337-10337/com.example.myapp W/System.err: 在 libcore.io.IoBridge.open(IoBridge.java:456)

01-18 11:34:46.235 10337-10337/com.example.myapp W/System.err: at java.io.FileInputStream.(FileInputStream.java:76)

01-18 11:34:46.235 10337-10337/com.example.myapp W/System.err:在 com.example.myapp.TabsActivity.exportDB(TabsActivity.java:183)

01-18 11:34:46.235 10337-10337/com.example.myapp W/System.err:在 com.example.myapp.TabsActivity.onOptionsItemSelected(TabsActivity.java:119)

【问题讨论】:

您是否尝试过使用File currentdb = new File(this.getDatabasePath("mydatabase.db").getPath());? - 即没有父级,并且获取路径不是对象的 toString 值。这假定文件名为 mydatabase.db(如果只是 mydatabase 则使用它)。 试过了,不行。我认为如果我创建一个数据库,它会自动将其存储在 data/.../databases/ 中,对吗?我不必喜欢把它放在那里,不是吗?还有它的标准存储方式是什么? mydatabase 还是 mydatabase.db?对不起,如果这是一个愚蠢的问题,我以前从未在 android 上处理过数据库。 默认情况下,数据库存储在data/data/*package*/databases,但它不需要存储在那里。但是,我建议添加日志记录(例如 Log.d("DBPATH","Database path is " + currentDBPath); 或至少包括日志中的堆栈跟踪(取消注释 //e.printStackTrace();)。使用结果编辑您的问题。 就是这样做的。我的手机没有root 会不会是这个问题? 嗯不确定。但是刚刚回答您需要制作目录。但是,我使用的是 Genymotion 模拟器,我认为它是根深蒂固的。所以答案对我有用。 【参考方案1】:

如下所示,问题可能与数据库无关,而可能与外部存储有关,因为目录不存在。解决方法是创建目录。希望以下内容会起作用(对我有用):-

    try 
        source = new FileInputStream(currentDB).getChannel();
        (new File(backupDB.getParent())).mkdirs(); //<<<<<<<<<<<<<< ADDED
        destination = new FileOutputStream(backupDB).getChannel();
        //destination.transferFrom(source, 0, source.size());
        source.close();
        destination.close();
     catch(IOException e) 
        e.printStackTrace();
        Toast.makeText(this, "Err:"+e, Toast.LENGTH_LONG).show();
    
为了测试,我已经注释掉了转移。 P.S.转移运行正常。 也可能由于权限问题(我的测试是在 genymotion 模拟器上进行的)。 刚刚在真机上测试过,如果不授权也会出现同样的错误。 刚刚在 Manifest 中的真实设备设置权限以及版本 > 23 的代码中进行了测试。复制然后工作。 :-

这可能有用Storage permission error in Marshmallow


获取您的代码并根据它进行调整(检查路径,参见输出):-

java.io.FileNotFoundException: /mnt/sdcard/storage/extSdCard/mydatabase:打开失败:ENOENT(没有这样的 文件或目录)

private void exportDB()
    File sd = Environment.getExternalStorageDirectory();
    File data = Environment.getDataDirectory();
    FileChannel source=null;
    FileChannel destination=null;
    String currentDBPath = "/data/"+ getPackageName() +"/databases/"+DatabaseHandler.DATABASE_NAME;
    String retreivedDBPAth = getDatabasePath(DatabaseHandler.DATABASE_NAME).getPath();
    String backupDBPath = "/storage/extSdCard/mydatabase";
    File currentDB = new File(data, currentDBPath);
    File backupDB = new File(sd, backupDBPath);
    File retrievedDB = new File(retreivedDBPAth);
    Log.d("PATHS", " CurrentDB=" +
            currentDBPath + "\n\t" + currentDB.getPath() +
            "\n\tExists=" + String.valueOf(currentDB.exists()) +
            "\nBackup=" + backupDBPath + "\n\t" + backupDB.getPath() +
            "\n\tExists=" + String.valueOf(backupDB.exists()) +
            "\nRetrieved DB=" + retreivedDBPAth + "\n\t" + retrievedDB.getPath() +
            "\n\tExists=" + String.valueOf(retrievedDB.exists())
    );
    try 
        source = new FileInputStream(currentDB).getChannel();
        destination = new FileOutputStream(backupDB).getChannel();
        //destination.transferFrom(source, 0, source.size());
        source.close();
        destination.close();
     catch(IOException e) 
        e.printStackTrace();
        Toast.makeText(this, "Err:"+e, Toast.LENGTH_LONG).show();
    

ENOENT 不是用于数据库,而是用于外部存储,按照:-

01-18 11:11:32.017 2689-2689/? D/PATHS:  CurrentDB=/data/example.com.so48304909_spinner/databases/spinnerExample
                                            /data/data/example.com.so48304909_spinner/databases/spinnerExample
                                            Exists=true
                                        Backup=/storage/extSdCard/mydatabase
                                            /mnt/sdcard/storage/extSdCard/mydatabase
                                            Exists=false
                                        Retrieved DB=/data/data/example.com.so48304909_spinner/databases/spinnerExample
                                            /data/data/example.com.so48304909_spinner/databases/spinnerExample
                                            Exists=true
01-18 11:11:32.021 2689-2689/? W/System.err: java.io.FileNotFoundException: /mnt/sdcard/storage/extSdCard/mydatabase: open failed: ENOENT (No such file or directory)
01-18 11:11:32.021 2689-2689/? W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:416)
01-18 11:11:32.021 2689-2689/? W/System.err:     at java.io.FileOutputStream.<init>(FileOutputStream.java:88)
01-18 11:11:32.021 2689-2689/? W/System.err:     at java.io.FileOutputStream.<init>(FileOutputStream.java:73)
01-18 11:11:32.021 2689-2689/? W/System.err:     at example.com.so48304909_spinner.MainActivity.exportDB(MainActivity.java:162)
01-18 11:11:32.021 2689-2689/? W/System.err:     at example.com.so48304909_spinner.MainActivity.onCreate(MainActivity.java:38)
01-18 11:11:32.021 2689-2689/? W/System.err:     at android.app.Activity.performCreate(Activity.java:5008)
01-18 11:11:32.021 2689-2689/? W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
01-18 11:11:32.021 2689-2689/? W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
01-18 11:11:32.021 2689-2689/? W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
01-18 11:11:32.021 2689-2689/? W/System.err:     at android.app.ActivityThread.access$600(ActivityThread.java:130)
01-18 11:11:32.021 2689-2689/? W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
01-18 11:11:32.021 2689-2689/? W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:99)
01-18 11:11:32.021 2689-2689/? W/System.err:     at android.os.Looper.loop(Looper.java:137)
01-18 11:11:32.021 2689-2689/? W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:4745)
01-18 11:11:32.021 2689-2689/? W/System.err:     at java.lang.reflect.Method.invokeNative(Native Method)
01-18 11:11:32.021 2689-2689/? W/System.err:     at java.lang.reflect.Method.invoke(Method.java:511)
01-18 11:11:32.021 2689-2689/? W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
01-18 11:11:32.021 2689-2689/? W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
01-18 11:11:32.021 2689-2689/? W/System.err:     at dalvik.system.NativeStart.main(Native Method)
01-18 11:11:32.021 2689-2689/? W/System.err: Caused by: libcore.io.ErrnoException: open failed: ENOENT (No such file or directory)
01-18 11:11:32.021 2689-2689/? W/System.err:     at libcore.io.Posix.open(Native Method)
01-18 11:11:32.021 2689-2689/? W/System.err:     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
01-18 11:11:32.021 2689-2689/? W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:400)
01-18 11:11:32.021 2689-2689/? W/System.err:    ... 18 more

【讨论】:

太棒了,它现在完美运行。非常感谢! 我的猜测是,您与 ENOENT 的修复混淆了第一个导致第二个跳入。不使用 toasts 的好理由 :)

以上是关于试图在 Android 中复制 SQLite 数据库并得到“没有这样的文件或目录”的主要内容,如果未能解决你的问题,请参考以下文章

android中使用了哪些版本的SQLite? [复制]

Android和SQLite [重复]

Android开发怎么查看和管理sqlite数据库

如何在 Android sqlite 中使用准备好的语句? [复制]

Sqlite数据库问题android

斯威夫特和 SQLite