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);
}
Вам необходимо выполнить этот код, прежде чем взаимодействовать с любым внешним процессом чтения, записи.