Исключение «Ошибка открытия: EACCES (В доступе отказано)» на Android


298

я получаю

открыть не удалось: EACCES (Permission denied)

на линии OutputStream myOutput = new FileOutputStream(outFileName);

Я проверил рут и попробовал android.permission.WRITE_EXTERNAL_STORAGE.

Как я могу решить эту проблему?

try {
    InputStream myInput;

    myInput = getAssets().open("XXX.db");

    // Path to the just created empty db
    String outFileName = "/data/data/XX/databases/"
            + "XXX.db";

    // Open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(outFileName);

    // Transfer bytes from the inputfile to the outputfile
    byte[] buffer = new byte[1024];
    int length;
    while ((length = myInput.read(buffer)) > 0) {
        myOutput.write(buffer, 0, length);
    }

    // Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();
    buffer = null;
    outFileName = null;
}
catch (IOException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}

У меня была такая же проблема на планшете Android, но моя ситуация может быть уникальной, поэтому я сообщаю о своем решении здесь в комментарии. Ошибка произошла, когда приложение попыталось получить доступ к каталогу / data / data / myapp / foo, в котором было более 50 XML-файлов. Приложение не очистило папку из-за ошибки. После удаления некоторых старых файлов ошибка исчезла. Я не знаю, почему. Это может быть проблема общего устройства Android.
Хонг

Это решило меня: stackoverflow.com/questions/33666071/…
partho

Ответы:


236

У меня была такая же проблема ... Это <uses-permissionбыло не в том месте. Это правильно:

 <manifest>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        ...
        <application>
            ...
            <activity> 
                ...
            </activity>
        </application>
    </manifest> 

uses-permissionТег должен быть вне applicationтега.


2
дело в том, что разрешение на использование должно быть вне приложения
user462990

3
Я получаю предупреждение: « <uses-permission>тег появляется после <application>тега»
mr5

11
ВНИМАНИЕ! В андроиде 4.4.4 не используйте параметр android:maxSdkVersion="18". Это генерировало это исключение
guisantogui

1
Это разрешение применяется начиная с уровня API 19. До уровня API 19 это разрешение не применяется, и все приложения по-прежнему имеют доступ для чтения из внешнего хранилища.
Зар Э Ахмер

1
я использую API lvl 15, я получаю ошибку при попытке переместить файл на OTG USB Stick
Рави Мехта

330

Для 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" />

Официальную документацию о запросе разрешений для API 23+ можно найти на странице https://developer.android.com/training/permissions/requesting.html.


13
Просто чтобы уточнить, чтобы это работало, действие должно обработать ответ на запрос разрешения деятельности. См. Developer.android.com/training/permissions/… для более подробной информации.
kldavis4

Полезная ссылка с пояснениями и примерами здесь inthecheesefactory.com/blog/…
Пол Александр

1
разве это не плохо? в отношении пользовательского опыта.
М. Усман Хан

5
Но где я могу это использовать? например, если я хочу сделать снимок, должен ли я запускать verifyStoragePermissions перед startActivityForResult или в onActivityResult? это действительно смущает меня.
Киви Ли

3
Спасибо, это решит мою проблему. просто примечание: если кто-то не может разрешить «Manifest.permission», вам просто нужно импортировать «import android.Manifest».
Oubaida AlQuraan

169

У Google появилась новая функция на 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/training/data-storage/compatibility


@ Билли, я заметил, что это происходит только на устройствах с API 29. Поэтому я искал изменения в поставщике файлов
Uriel Frankel

Наконец-то получил cloudtestingscreenshotter_lib.aar для работы с этой строкой, добавленной в манифест androidTest, большое спасибо за эту находку.
бко

6
Вы, сэр, сэкономили мне много времени. Много вещей стало болью для разработчика в Q. Я думаю, что этот ответ должен быть опубликован как отдельный вопрос и заслуживает большего количества голосов.
Санджив

Я хотел бы прочитать больше об этом милом трюке с черной магией, но, к сожалению, ссылка возвращает ошибку 404 ... В любом случае, спасибо
SadSido

его предупреждение android:requestLegacyExternalStorage="true"это не сломает более низкие версии RYT? @UrielFrankel
Sur

58

Я наблюдал это один раз при запуске приложения внутри эмулятора. В настройках эмулятора необходимо правильно указать размер внешнего хранилища («SD-карта»). По умолчанию поле «внешнее хранилище» пустое, и это, вероятно, означает, что такого устройства нет, и EACCES выбрасывается, даже если в манифесте предоставляются разрешения.


51

В дополнение ко всем ответам, убедитесь, что вы не используете свой телефон в качестве USB-накопителя.

У меня была такая же проблема в HTC Sensation при включенном режиме USB-накопителя. Я все еще могу отлаживать / запускать приложение, но не могу сохранить на внешнее хранилище.


Спасибо человек, хотя я запрашивал разрешения от пользователя во время выполнения. Эта ошибка произошла на эмуляторе.
Sharp Edge

1
Когда я подключаю устройство Samsung Galaxy S6, оно сначала предоставляет опцию «Разрешить доступ к данным устройства» с помощью «DENY» или «ALLOW», а также из панели уведомлений я получаю опцию «Использовать USB для 1. MTP 2. PTP 3. MIDI». Устройства 4. Зарядка. Какой выбрать?
testsingh

34

Добавить андроида: requestLegacyExternalStorage = "истина" в Android Manifest Он работал с Android 10 (Q) в SDK 29+
или После перенастройки Android X .

 <application
    android:name=".MyApplication"
    android:allowBackup="true"
    android:hardwareAccelerated="true"
    android:icon=""
    android:label=""
    android:largeHeap="true"
    android:supportsRtl=""
    android:theme=""
    android:requestLegacyExternalStorage="true">

Ух ты отлично работает, это был ответ, который я искал, отлично, спасибо @rhaldar, ты спас мой день
Аюш Катувал

29

Моя проблема была с "TargetApi (23)", которая необходима, если ваш minSdkVersion ниже 23.

Итак, у меня есть запрос на разрешение со следующим фрагментом

protected boolean shouldAskPermissions() {
    return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);
}

@TargetApi(23)
protected void askPermissions() {
    String[] permissions = {
            "android.permission.READ_EXTERNAL_STORAGE",
            "android.permission.WRITE_EXTERNAL_STORAGE"
    };
    int requestCode = 200;
    requestPermissions(permissions, requestCode);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
// ...
    if (shouldAskPermissions()) {
        askPermissions();
    }
}

28

Решение для Android Q :

<application ...
    android:requestLegacyExternalStorage="true" ... >

Ты спас мой день. Разрешение предоставлено, но Glide не может читать изображения, пока я не установлю это.
leegor

Внимание: Android 11 полностью удалит устаревший доступ в августе 2020 года, поэтому лучше обновите доступ к файлам, чтобы использовать Storage Access Framework (SAF) для своих приложений
dimib

16

Я испытываю то же самое. Я обнаружил, что если вы идете в Настройки -> Диспетчер приложений -> Ваше приложение -> Разрешения -> Включить хранилище , это решает проблему.


1
Я не могу найти этот раздел?
Эван Севи

13

Оказалось, это была глупая ошибка, так как мой телефон все еще был подключен к настольному ПК и я не осознавал этого.

Поэтому пришлось отключить USB-соединение, и все работало нормально.


работал для меня также. Но почему это работает? какая разница не подключение USB к ПК.
user13107

Хороший вопрос. Я никогда не исследовал это дальше. Я предполагаю, что в момент подключения устройства блокировка записи происходит из системы (поэтому она может эмулировать USB-устройство на вашем компьютере). Может быть, это для того, чтобы избежать противоречивых данных. Не уверен, хотя.
Тобиас Райх

Я нашел причину здесь stackoverflow.com/questions/7396757/… также см. Мой ответ stackoverflow.com/a/43863548/1729501
user13107

13

У меня была такая же проблема на Samsung Galaxy Note 3, под управлением CM 12.1. Проблема для меня заключалась в том, что у меня было

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

и должен был использовать это, чтобы взять и сохранить пользовательские фотографии. Когда я попытался загрузить те же самые фотографии в ImageLoader, я получил (Permission denied)ошибку. Решение было явно добавить

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

так как вышеупомянутое разрешение ограничивает только разрешение на запись до API версии 18, а вместе с ним разрешение на чтение


Не помог мне! Стоит попробовать! Спасибо.
Сакибой

9

В дополнение ко всем ответам, если клиенты используют Android 6.0, Android добавил новую модель разрешений для (Marshmallow).

Уловка: если вы нацелены на версию 22 или ниже, ваше приложение будет запрашивать все разрешения во время установки так же, как и на любом устройстве, работающем под ОС ниже Marshmallow. Если вы пытаетесь использовать эмулятор, то начиная с Android 6.0 и далее вам нужно явно перейти в настройки-> приложения-> YOURAPP -> разрешения и изменить разрешение, если вы его дали.


2
Невероятно, я провел 2 дня, пытаясь понять это. Каждый раз, когда я чувствую, что на Android все работает нормально, происходит нечто подобное.
Хайме Иван Сервантес

7

Странно после косой черты "/" перед моим новым файлом моя проблема была решена. Я изменил это:

File myFile= new File(Environment.getExternalStorageDirectory() + "newFile");

к этому:

File myFile= new File(Environment.getExternalStorageDirectory() + "/newFile");

1
Ничего странного здесь нет. В первой строке вы пытаетесь создать файл в том же каталоге, в котором находится ваш каталог внешнего хранилища. то есть /storage/.../somethingnewfile вместо /storage/.../something/newfile
Стефан

@ Stéphane Сама ошибка странная, если вы посмотрите на широкий диапазон ответов.
Даруш

3
Правильный способ сделать это - использовать созреватель File (dir, file)
Ник Кардосо,

@NickCardoso Вы также можете использовать File (String pathname). Похоже, вы здесь не поняли. Вопрос не в том, как использовать класс File. Диапазон ответов в этой теме показывает, насколько вводит в заблуждение эта ошибка и сколько возможных способов ее устранения. В моем случае ошибка была отсутствующей косой чертой. Некоторые люди нашли это полезным. Конечно, вы можете использовать свой собственный метод доступа к файлу. Идите вперед и опубликуйте свой ответ. Это может решить чью-то проблему.
Даруш

Вы не получаете суть. Если вы используете правильный конструктор, то ваш взлом не требуется. Мой комментарий был добавлен, чтобы помочь будущим читателям, введенным в заблуждение вашей ошибкой. Это не было личной критикой и не нуждалось в ответе
Ник Кардосо

6

У меня была такая же проблема, и ни одно из предложений не помогло. Но я нашел интересную причину для этого на физическом устройстве Galaxy Tab .

Когда USB-накопитель включен, разрешения на чтение и запись на внешнее хранилище не влияют. Просто отключите USB-накопитель, и с правильными разрешениями проблема будет решена.


2
Черт возьми, я просто потратил около 3 часов, работая вокруг. Дополнительно пришлось перезагрузить устройство, и оно заработало.
Огромное

5

Я ожидаю, что все ниже /dataбудет принадлежать «внутреннему хранилищу». Однако вы должны иметь возможность написать /sdcard.


5
Я тоже пробовал <использование-разрешения android: name = "android.permission.WRITE_INTERNAL_STORAGE" />. все тот же.
Мерт

1
Раздел / data, как правило, защищен от записи обычным (не root) пользователям, пытающимся получить обычный доступ к файлам. Для внутреннего хранения существуют специальные методы, особенно если вы хотите получить доступ к базам данных. На страницах разработчиков Android должны помочь вам в этом вопросе.
печки

5

Измените свойство разрешения в вашей /system/etc/permission/platform.xml
и группе необходимо упомянуть, как показано ниже.

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">
    <group android:gid="sdcard_rw" />
    <group android:gid="media_rw" />    
</uses-permission>

Платформа.xml заблокирована, пытаясь сделать это через оболочку adb, но мне нужен скрипт, который ADB позволит мне использовать для мода.
Джон

Потерпеть поражение. Поместите мое устройство в цикл загрузки.
Тобсе

5

У меня была такая же ошибка, когда я пытался записать изображение в папку DCIM / камера на Galaxy S5 (Android 6.0.1), и я понял, что только эта папка ограничена. Я просто мог написать в DCIM / любую папку, но не в камере. Это должно быть ограничение / настройка на основе бренда.


4

Когда ваше приложение относится к системному приложению, оно не может получить доступ к SD-карте.


4

имейте в виду, что даже если вы установили все правильные разрешения в манифесте: единственное место, в которое сторонним приложениям разрешено писать на вашу внешнюю карту, это «их собственные каталоги» (т.е. / sdcard / Android / data /), пытающиеся записать в в другом месте: вы получите исключение: EACCES (В доступе отказано)


3

Может быть, ответ таков:

на устройствах API> = 23, если вы устанавливаете приложение (приложение не является системным приложением), вы должны проверить разрешение на хранение в разделе «Настройки - приложения», для каждого приложения есть список разрешений, вы должны проверить его! пытаться


3

В моем случае я использовал библиотеку выбора файлов, которая возвращала путь к внешнему хранилищу, но он начинался с /root/. И даже с разрешением WRITE_EXTERNAL_STORAGE, предоставленным во время выполнения, я все равно получил ошибку EACCES (разрешение отклонено) .
Так что используйте, Environment.getExternalStorageDirectory()чтобы получить правильный путь к внешнему хранилищу.

Пример:
не могу написать: /root/storage/emulated/0/newfile.txt
могу написать: /storage/emulated/0/newfile.txt

boolean externalStorageWritable = isExternalStorageWritable();
File file = new File(filePath);
boolean canWrite = file.canWrite();
boolean isFile = file.isFile();
long usableSpace = file.getUsableSpace();

Log.d(TAG, "externalStorageWritable: " + externalStorageWritable);
Log.d(TAG, "filePath: " + filePath);
Log.d(TAG, "canWrite: " + canWrite);
Log.d(TAG, "isFile: " + isFile);
Log.d(TAG, "usableSpace: " + usableSpace);

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

Выход 1:

externalStorageWritable: true
filePath: /root/storage/emulated/0/newfile.txt
isFile: false
usableSpace: 0

Выход 2:

externalStorageWritable: true
filePath: /storage/emulated/0/newfile.txt
isFile: true
usableSpace: 1331007488

У меня была точно такая же проблема. Удаление rootчасти из пути решило мою проблему.
xabush


3

Для тех, кто приходит сюда из результатов поиска и ориентируется на Android 10: Android 10 (API 29) меняет некоторые разрешения, связанные с хранением.

Я исправил эту проблему, когда заменил свои предыдущие экземпляры Environment.getExternalStorageDirectory()(что устарело в API 29) наcontext.getExternalFilesDir(null) .

Обратите внимание, что context.getExternalFilesDir(type) может возвращать ноль, если место хранения недоступно, поэтому обязательно проверяйте это всякий раз, когда проверяете, есть ли у вас внешние разрешения.

Узнайте больше здесь .


2

Я создаю папку в / data / в моем init.rc (возиться с aosp на Nexus 7) и имел именно эту проблему.

Оказалось, что предоставления разрешения для папки rw (666) было недостаточно, и это должно было быть rwx (777), тогда все работало!


2

Применение разрешений на хранение после 6.0 можно обойти, если у вас есть рутированное устройство с помощью этих команд adb:

root@msm8996:/ # getenforce
getenforce
Enforcing
root@msm8996:/ # setenforce 0
setenforce 0
root@msm8996:/ # getenforce
getenforce
Permissive

1

Добавить разрешение в манифест.

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

3
Нет разрешенияandroid.permission.READ_INTERNAL_STORAGE
Райан Р

0

У меня была такая же проблема (API> = 23).

Решение https://stackoverflow.com/a/13569364/1729501 у меня сработало, но отключить приложение для отладки было непрактично.

Мое решение состояло в том, чтобы установить правильный драйвер устройства ADB на Windows. Драйвер USB Google не работает для моего устройства.

ШАГ 1: Загрузите драйверы adb для вашего устройства.

ШАГ 2: Зайдите в диспетчер устройств -> другие устройства -> найдите записи со словом «adb» -> выберите «Обновить драйвер» -> укажите местоположение на шаге 1


0

после добавления разрешения решил мою проблему

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

0

Добавить зависимости gradle

implementation 'com.karumi:dexter:4.2.0'

Добавьте ниже код в вашей основной деятельности.

import com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
    @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_splash);

    new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {


                checkMermission();
            }
        }, 4000);
    }

    private void checkMermission(){
        Dexter.withActivity(this)
                .withPermissions(
                        android.Manifest.permission.READ_EXTERNAL_STORAGE,
                        android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        android.Manifest.permission.ACCESS_NETWORK_STATE,
                        Manifest.permission.INTERNET
                ).withListener(new MultiplePermissionsListener() {
            @Override
            public void onPermissionsChecked(MultiplePermissionsReport report) {
                if (report.isAnyPermissionPermanentlyDenied()){
                    checkMermission();
                } else if (report.areAllPermissionsGranted()){
                    // copy some things
                } else {
                    checkMermission();
                }

            }
            @Override
            public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
                token.continuePermissionRequest();
            }
        }).check();
    }

0

В моем случае ошибка появлялась на линии

      target.createNewFile();

так как я не мог создать новый файл на SD-карте, поэтому мне пришлось использовать подход DocumentFile.

      documentFile.createFile(mime, target.getName());

Для вышеуказанного вопроса проблема может быть решена с помощью этого подхода,

    fos=context.getContentResolver().openOutputStream(documentFile.getUri());

См. Также эту ветку. Как использовать новый API доступа к SD-карте, представленный для Android 5.0 (Lollipop)?

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.