Как открыть существующую базу данных SQLite с помощью объекта Uri? - PullRequest
0 голосов
/ 02 января 2019

Я использую 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 голосов
/ 18 июля 2019

Вы не должны пытаться открыть базу данных SQLite из Uri.

SQLiteDatabase предназначен для работы непосредственно с файловой системой: он должен блокировать и разблокировать файл базы данных и управлять отдельными файлами журналирования с опережением записи (-shm и -wal), в то время как Uri не обязательно ссылается на какой-либо контент в файле: // схемы. Вместо этого это может быть что угодно, от https: // или content: // до пользовательских схем, определенных приложением.

Тем более, что Android 7.0 Google навязывает использование контента: // uris для обмена файлами между приложениями (это как раз ваш случай). Взяты отсюда: https://developer.android.com/about/versions/nougat/android-7.0-changes.html:

Для приложений, ориентированных на Android 7.0, платформа Android применяет политику API StrictMode, которая запрещает показ URI file: // вне вашего приложения. Если намерение, содержащее файловый URI, покидает ваше приложение, приложение завершается ошибкой с исключением FileUriExposedException.

Чтобы обмениваться файлами между приложениями, вы должны отправить 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 из другого приложения (возможно, стороннего), я настоятельно рекомендую вам работать с базой данных в отдельном потоке / AsyncTask / и т. Д. Вы никогда не знаете, сколько петабайт вы получаете: )

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...