File Chooser на новой ОС - файл не найден

В моем приложении для Android мне нужно загрузить текстовый файл из хранилища, используя диалог выбора файлов. Некоторое время назад я следовал инструкциям в этой теме выбора файлов Android (оригинальный ответ).

На телефоне с Android 4.2.2 (API 17) все отлично работает. Этот код (на самом деле как uri.getPath() сам) возвращает реальный путь к файлу:

public static String getPath(Context context, Uri uri) throws URISyntaxException {
    if ("content".equalsIgnoreCase(uri.getScheme())) {
        String[] projection = { "_data" };
        Cursor cursor = null;
        try {
            cursor = context.getContentResolver().query(uri, projection, null, null, null);
            int column_index = cursor.getColumnIndexOrThrow("_data");
            if (cursor.moveToFirst()) {
                return cursor.getString(column_index);
            }
        } catch (Exception e) {
            ...
        }
        ...
    }
    ...
}

Это возвращает что-то вроде этого: /storage/sdcard1/Directory/myFile.txt

..и я могу дальше работать с файлом.

Однако на телефонах с Android 7 и 8 (API 24-26) cursor.getString(column_index) всегда возвращается nullи uri.getPath() возвратные пути, такие как:

  • /document/254 - Android 8 (внешнее хранилище)
  • /document/primary:myFile.txt - Android 8 (внутренняя память)
  • /document/C5F9-13FC:myFile.txt - Android 7

... и когда я хочу работать с файлом, созданным new File(path) и читать его содержимое с BufferedReader, я получаю FileNotFoundException,

Я не думаю, что это проблема с разрешениями, потому что когда я читаю файл с жестко закодированным путем, используя следующий код, все работает нормально:

File storage = Environment.getExternalStorageDirectory();
File file = new File(storage, fileName);

Мой вопрос:

Есть ли какой-нибудь способ получить реальный путь к файлу от средства выбора файлов, или я должен решить эту проблему на устройствах с более новым Android API, совершенно иначе, как при использовании внешней библиотеки?

1 ответ

Я нашел решение здесь.

Проблема заключалась в том, что я хотел прочитать файл, используя следующий код:

File file = new File(intent.getData().getPath());
BufferedReader br = new BufferedReader(new FileReader(file));

Вместо этого я должен использовать это:

InputStream is = getContentResolver().openInputStream(intent.getData());
BufferedReader br = new BufferedReader(new InputStreamReader(is));

Добавить это в файл манифеста

  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

Затем запросите разрешение во время выполнения, как показано ниже

// Check whether this app has write external storage permission or not.
int writeExternalStoragePermission = ContextCompat.checkSelfPermission(ExternalStorageActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
// If do not grant write external storage permission.
if(writeExternalStoragePermission!= PackageManager.PERMISSION_GRANTED)
{
    // Request user to grant write external storage permission.
    ActivityCompat.requestPermissions(ExternalStorageActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION);
}

Вам необходимо выполнить этот код, прежде чем взаимодействовать с любым внешним процессом чтения, записи.

Другие вопросы по тегам