Подтвердить что ты не робот

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. Звучит скорее как проблема с потоками.

4b9b3361

Ответ 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"));