Open failed: EACCES (разрешение отклонено)
У меня очень странная проблема с доступом к хранилищу на некоторых устройствах. Приложение работает на моих тестовых устройствах (Nexus 4 и 7, Samsung GS5). Все мои устройства под управлением Android 4.4.2. Но я получил много писем от пользователей, заявив, что приложение не может писать в хранилище (ни внутреннее хранилище, ни SD-карта). Из файла журнала, полученного от отзывов пользователей, я вижу, что проблема заключается в следующем коде:
try {
if (fStream == null) {
fStream = new FileOutputStream(filename, true);
}
fStream.write(data, 0, bytes);
return;
} catch (IOException ex) {
ex.printStackTrace();
}
Он выдает исключение в строке fStream = new FileOutputStream (filename, true); при создании FileOutputStream.
Журнал стека:
W/System.err( 8147): Caused by: java.io.FileNotFoundException: /storage/emulated/0/my_folder/test_file_name.png: open failed: EACCES (Permission denied)
w/System.err( 8147): at libcore.io.IoBridge.open(IoBridge.java:409)
W/System.err( 8147): at java.io.FileOutputStream.<init>(FileOutputStream.java:88)
W/System.err( 8147): at java.io.FileOutputStream.<init>(FileOutputStream.java:128)
W/System.err( 8147): at myapp.save(SourceFile:515)
W/System.err( 8147): ... 8 more
W/System.err( 8147): Caused by: libcore.io.ErrnoException: open failed: EACCES (Permission denied)
W/System.err( 8147): at libcore.io.Posix.open(Native Method)
W/System.err( 8147): at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
W/System.err( 8147): at libcore.io.IoBridge.open(IoBridge.java:393)
W/System.err( 8147): ... 11 more
В AndroidManifest.xml объявлены следующие разрешения:
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Я подтвердил, что пользователи используют правильное приложение на SD-карте. И что более странно, так это то, что он не может писать и на внутреннее хранилище. Как это может произойти, если у меня есть права на чтение и запись? Пользователи говорят, что они не подключают свои устройства к ПК в это время.
Update
Оказывается, я слишком часто вызываю open и close FileOutputStream, что в какой-то момент бросает FileNotFoundException. Звучит скорее как проблема с потоками.
Ответы
Ответ 1
Я столкнулся с подобной проблемой некоторое время назад.
Ваша проблема может быть в двух разных областях. Это либо то, как вы создаете файл для записи, либо ваш метод записи может быть ошибочным, поскольку он зависит от телефона.
Если вы записываете файл в определенное место на SD-карте, попробуйте использовать переменные среды. Они всегда должны указывать на правильное местоположение. Вот пример для записи в папку загрузок:
java.io.File xmlFile = new java.io.File(Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
+ "/Filename.xml");
Если вы записываете файл во внутреннее хранилище приложения. Попробуйте этот пример:
java.io.File xmlFile = new java.io.File((getActivity()
.getApplicationContext().getFileStreamPath("FileName.xml")
.getPath()));
Лично я полагаюсь на внешние библиотеки для обработки потоковой передачи в файл. Этот еще не подвел меня.
org.apache.commons.io.FileUtils.copyInputStreamToFile(is, file);
Я потерял данные слишком много раз из-за неудачной команды записи, поэтому я полагаюсь на хорошо известные и проверенные библиотеки для своего тяжелого ввода-вывода.
Если файлы большие, вы также можете посмотреть, как работает ввод-вывод в фоновом режиме, или использовать обратные вызовы.
Если вы уже используете переменные среды, это может быть проблема с разрешениями. Проверьте Джастин Фидлер ответ ниже.
Ответ 2
Для API 23+ вам необходимо запросить разрешения на чтение и запись, даже если они уже находятся в вашем манифесте.
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
/**
* Checks if the app has permission to write to device storage
*
* If the app does not has permission then the user will be prompted to grant permissions
*
* @param activity
*/
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Ответ 3
Приложениям с таргетингом на Android Q по умолчанию предоставляется фильтрованное представление во внешнем хранилище. Быстрое решение этой проблемы - добавить этот код в AndroidManifest.xml:
<manifest ... >
<!-- This attribute is "false" by default on apps targeting Android Q. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
Подробнее об этом читайте здесь:https://developer.android.com/preview/privacy/scoped-storage
Ответ 4
В моем случае у меня был неправильный случай в
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
android.permission
должен быть строчным, а вся цепочка в нашем источнике имеет верхний регистр.
Ответ 5
Я также столкнулся с той же проблемой.
После тяжелой работы я обнаружил, что было не так в моем случае.
Мое устройство было подключено к компьютеру через USB-кабель.
Существуют типы подключений USB, таких как Mass Storage, Media Device (MTP), Camera (PTP) и т.д.
Мой тип подключения был - "Mass Storage", и это вызывало проблемы.
Когда я изменил тип подключения, проблема была решена.
Всегда помните о доступе к файловой системе на устройстве Android: -
НЕ ПОДКЛЮЧАЙТЕ КАК МАСШТАБНОЕ ХРАНЕНИЕ к компьютеру/ПК.
Ответ 6
В моем случае это были проблемы с разрешениями.
Уловка заключается в том, что на устройстве с Android 4.0.4 я получил доступ к файлу без какой-либо ошибки или исключения. А на устройстве с Android 5.1 он вышел из строя с исключением ACCESS (open failed: EACCES (Permission denied)).
Обработала его, добавив следующие разрешения для файла манифеста:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Поэтому я предполагаю, что это разница между управлением разрешениями в версиях ОС, что приводит к сбоям.
Ответ 7
Сначала дайте или проверьте разрешения, например
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Если эти два разрешения в порядке, то проверьте, что выходные потоки находятся в правильном формате.
Пример:
FileOutputStream fos=new FileOutputStream(Environment.getExternalStorageDirectory()+"/rahul1.jpg");
Ответ 8
Я столкнулся с той же проблемой и обнаружил, что я должен запрашивать разрешения во время выполнения, даже если я объявил это в манифесте. Как сказал Джастин Фидлер.
Официальная документация об этом здесь: https://developer.android.com/training/permissions/requesting.html
Моя реализация немного отличается от ответа Джастина Фидлера на то, что он также реализует v4-фрагмент метода onRequestPermissionsResult для обработки запроса запроса разрешений.
public static final int REQUEST_EXTERNAL_PERMISSION_CODE = 666;
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public static final String[] PERMISSIONS_EXTERNAL_STORAGE = {
READ_EXTERNAL_STORAGE,
WRITE_EXTERNAL_STORAGE
};
public boolean checkExternalStoragePermission(Activity activity) {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
return true;
}
int readStoragePermissionState = ContextCompat.checkSelfPermission(activity, READ_EXTERNAL_STORAGE);
int writeStoragePermissionState = ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE);
boolean externalStoragePermissionGranted = readStoragePermissionState == PackageManager.PERMISSION_GRANTED &&
writeStoragePermissionState == PackageManager.PERMISSION_GRANTED;
if (!externalStoragePermissionGranted) {
requestPermissions(PERMISSIONS_EXTERNAL_STORAGE, REQUEST_EXTERNAL_PERMISSION_CODE);
}
return externalStoragePermissionGranted;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (requestCode == REQUEST_EXTERNAL_PERMISSION_CODE) {
if (checkExternalStoragePermission(getActivity())) {
// Continue with your action after permission request succeed
}
}
}
}
Ответ 9
В моем случае я использовал опцию android:isolatedProcess="true"
для service
в AndroidManifest.xml
.
Как только я удалил его, ошибка исчезла...
Ответ 10
Также я нашел решение для своего пути.
Перед запуском приложения я предоставил root файловому проводнику и не отключил разрешение на запись/чтение при выходе из приложения.
Мое приложение не может использовать внешнюю память, в то время как я перезаряжал устройство для сброса всех разрешений.
Ответ 11
У меня такая же проблема, но
Иногда самый сложный вопрос дает простой ответ.
Я перепроверяю разрешения манифеста и там WAS_NOT write permision
стыд меня!!!
Ответ 12
Если клиенты используют Android 6.0, Android добавила новую модель разрешения для (Marshmallow).
Trick: Если вы настроите таргетинг на версию 22 или ниже, ваше приложение будет запрашивать все разрешения во время установки так же, как и на любом устройстве, работающем под ОС ниже Marshmallow
Ответ 13
В моем случае проблема заключалась в том, что конфигурация WIFI, статическая, имела конфликт с другим устройством, использующим тот же IP-адрес.
Ответ 14
@Уриэль Франкель прав, что доступ к хранилищу Android 10 изменился. Но правильный способ - не использовать устаревший флаг хранения, а запросить хранилище вашего приложения следующим образом:
val screenShotDirPath = getApplication<Application>().getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.path
getExternalFilesDir - это то, что вам нужно.
Ответ 15
в моем случае я забыл добавить/перед именем файла после того, как добавил, я избавился от него
bitmap.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(Environment.getExternalStorageDirectory()+"/arjunreddy.png"));