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

时间:2019-01-02 14:26:36

标签: 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);

1 个答案:

答案 0 :(得分:0)

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

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

尤其是从Android 7.0开始,Google强制使用content:// uris在应用之间共享文件(这正是您的情况)。从这里获取:https://developer.android.com/about/versions/nougat/android-7.0-changes.html

  

对于面向Android 7.0的应用,Android框架会实施StrictMode API策略,该策略禁止在应用外部公开file:// URI。如果包含文件URI的意图离开您的应用程序,则该应用程序将失败,并出现FileUriExposedException异常。

     

要在应用程序之间共享文件,应发送content:// URI并授予对该URI的临时访问权限。授予此权限的最简单方法是使用FileProvider类。有关权限和共享文件的更多信息,请参见共享文件。

相反,您应该获取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流时,我强烈建议您在单独的Thread / AsyncTask / etc中使用数据库。您永远不知道会收到多少PB: )