Виняток "відкрито не вдалося: EACCES (в дозволі відмовлено)" на Android


297

Я отримую

не вдалося відкрити: 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
УВАГА У Android 4.4.4 не використовуйте параметр android:maxSdkVersion="18". Це породжувало цей виняток
guisantogui

1
Цей дозвіл застосовується починаючи з рівня 19 API. Перед рівнем 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


1
це не погано? щодо досвіду користувачів.
М. Усман Хан

5
Але де я його використовую? Наприклад, якщо я хочу сфотографувати, чи потрібно запускати verifyStoragePermissions перед запускомActivityForResult або на onActivityResult? це мене справді бентежить.
Ківі Лі

3
Завдяки цьому вирішіть мою проблему. лише примітка: якщо хтось не може вирішити "Manifest.permission", вам просто потрібно імпортувати "імпорт android.Manifest".
Oubaida AlQuraan

166

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


@Billy Я помітив, що це відбувається лише на пристроях з api 29. Тож я шукав зміни у постачальниках файлів
Uriel Frankel

Нарешті отримав cloudtestingscreenshotter_lib.aar для роботи з цим рядком, доданим до маніфесту androidTest, дуже дякую за цю знахідку.
bko

6
Ви, пане, врятували мені багато часу. Багато запитань стало проблемою для розробника в Q. Я думаю, що цю відповідь слід розмістити як окреме запитання і заслуговує на більшу кількість результатів.
sanjeev

Я хотів би прочитати більше про цю приємну маленьку чорну магічну хитрість, але, на жаль, посилання повертає помилку 404 ... Все одно спасибі
SadSido

це попереджає android:requestLegacyExternalStorage="true"це звик ламати нижчі версії ryt? @UrielFrankel
Santanu Sur

58

Я це спостерігав один раз під час запуску програми всередині емулятора. У налаштуваннях емулятора потрібно правильно вказати розмір зовнішньої пам’яті («SD Card»). За замовчуванням поле "зовнішнє сховище" порожнє, і це, ймовірно, означає, що такого пристрою немає, і EACCES кидається, навіть якщо дозволу надано в маніфесті.


51

Окрім усіх відповідей, переконайтеся, що ви не використовуєте свій телефон як USB-накопичувач.

У мене була така ж проблема з увімкненим режимом зберігання HTC у режимі зберігання USB. Я все ще можу налагоджувати / запускати додаток, але не можу зберегти його на зовнішньому сховищі.


Дякую, хоч я хоч і вимагав дозволів у користувача під час виконання. Ця помилка сталася на емуляторі.
Гострий край

1
Коли я підключаю пристрій Samsung Galaxy S6, він спочатку дає опцію "Дозволити доступ до даних пристрою" за допомогою "DENY" або "ALLOW", а також із панелі повідомлень я отримую опцію Використовувати USB для 1. MTP 2. PTP 3. MIDI Пристрої 4. Зарядка. Який вибрати?
тестування

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 до ПК.
користувач13107

Хороше питання. Я ніколи більше цього не досліджував. Я б здогадувався, що в систему підключено запис із моменту підключення пристрою (щоб він міг наслідувати пристрій 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

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

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

@NickCardoso Ви також можете використовувати файл (ім'я строки). Схоже, ви тут не розумієте. Питання не в тому, як використовувати клас File. Спектр відповідей у ​​цій темі показує, наскільки ця помилка вводить в оману та скільки можливих способів її усунення. У моєму випадку помилка була відсутньою косою рисою. Деякі люди вважають це корисним. Впевнені, що ви можете використовувати свій власний метод доступу до файлу. Вперед та опублікуйте свою відповідь. Це може вирішити чиюсь проблему.
Даруш

Ви не отримуєте суть. Якщо ви використовуєте правильний конструктор, ваш хак не потрібен. Мій коментар був доданий, щоб він міг допомогти будь-яким майбутнім читачам, введеним в оману вашою помилкою. Це не була особиста критика і не потребувала відповіді
Нік Кардосо

6

У мене була така ж проблема, і жодна пропозиція не допомогла. Але я знайшов цікаву причину для цього на фізичному пристрої Galaxy Tab .

Якщо USB-накопичувач увімкнено, дозвіл на читання та запис на зовнішній носій не впливає. Просто вимкніть USB-накопичувач і з правильними дозволами у вас виникне проблема.


2
Чорт забираю, я просто провів 3 години, працюючи. Додатково мені довелося перезавантажити пристрій, і воно спрацювало. Дякую велике
crgarridos

5

Я б очікував, що все, що нижче, /dataналежить до "внутрішнього сховища". Однак ви повинні мати можливість писати /sdcard.


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

1
Розділ / дані, як правило, захищений від запису для звичайних (некореневих) користувачів, які намагаються отримати звичайний доступ до файлів. Для внутрішнього зберігання є спеціалізовані методи для цього, особливо якщо ви хочете отримати доступ до баз даних. На сторінках розробників 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>

platform.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
Ryan R

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

Додайте залежність градуля

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.