android - 如何使用 Uri 对象打开现有的 SQLite 数据库?

标签 android database sqlite uri

我正在使用 Intent.ACTION_GET_CONTENT 选择一个文件。

onActivityResult 方法中,我得到了 Uri:

Uri selectedfile = data.getData();

如何使用 Uri 对象 selectedfile 打开 SQLite 数据库?这不起作用:

SQLiteDatabase database = SQLiteDatabase.openDatabase(selectedfile.getPath(), null, SQLiteDatabase.OPEN_READONLY);

最佳答案

您不应该尝试从 Uri 打开 SQLiteDatabase。

SQLiteDatabase 被设计为直接与文件系统一起工作:它需要锁定和解锁数据库文件并管理单独的预写日志记录(-shm 和-wal)文件,而 Uri 不一定引用 file://中的任何内容模式。相反,它可以是任何内容,从 https://或 content://到自定义应用程序定义的模式。

特别是自 Android 7.0 以来,Google 强制使用 content://uri 在应用程序之间共享文件(这正是您的情况)。取自此处:https://developer.android.com/about/versions/nougat/android-7.0-changes.html :

For apps targeting Android 7.0, the Android framework enforces the StrictMode API policy that prohibits exposing file:// URIs outside your app. If an intent containing a file URI leaves your app, the app fails with a FileUriExposedException exception.

To share files between applications, you should send a content:// URI and grant a temporary access permission on the URI. The easiest way to grant this permission is by using the FileProvider class. For more information on permissions and sharing files, see Sharing Files.

相反,您应该获取 ContentResolver,从中打开 uri InputStream 并将流内容保存到本地临时文件,然后在其上使用 SQLiteDatabase.openDatabase(filePath):

void openDatabaseFromFileDialog() {
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT).setType("*/*");
    startActivityForResult(Intent.createChooser(intent, "Select a database"), DB_FILE_REQUEST);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if(requestCode == DB_FILE_REQUEST && resultCode == RESULT_OK) {
        Uri dataUri= data.getData();
        openDatabaseFromUri(dataUri);
    } else {
        super.onActivityResult(requestCode, resultCode, data);
    }
}

void openDatabaseFromUri(Uri uri) {
    InputStream inputStream = application.getContentResolver().openInputStream(uri);

    File file = File.createTempFile("sqlite", "");

    FileOutputStream outputStream = new FileOutputStream(file);
    byte[] buff = new byte[1024];
    int read;
    while ((read = inputStream.read(buff, 0, buff.length)) > 0)
        outputStream.write(buff, 0, read);
    inputStream.close();
    outputStream.close();

    openDatabaseFromFile(file.getPath());
}

void openDatabaseFromFile(String filePath) {
    // your code here
}

此外,当您从另一个应用程序(可能是第三方)获取 SQLite 流时,我强烈建议您在单独的线程/AsyncTask/等中使用数据库。您永远不知道您收到了多少 PB: )

关于android - 如何使用 Uri 对象打开现有的 SQLite 数据库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54008073/

相关文章:

java - SEservice中Executor的使用方法(Open Mobile API for Android 9.0)

android - 错误 - 无法联系到谷歌服务器

php - 在数据库中存储折线(谷歌地图)的更好方法是什么?

java - 应用程序在 Android/SQLITE 错误中停止/

android - 找不到参数的方法 firebaseAppDistribution()

android - React Native App 在 "--variant=release"命令 : Signed APK 上崩溃

database - 如果不以 wp_ 开头但包含它,则重命名 phpmyadmin 中的表前缀

database - 数据库的内部运作

java - 如何使用带有加密功能的 SQLiteJDBC 库 (sqlite-jdbc-crypt)

ruby-on-rails - 使用sqlite3进行开发的Rails应用程序不会部署到heroku中