Wyjątek „otwarte niepowodzenie: EACCES (odmowa dostępu)” na Androidzie

297

staje się

otwarte nieudane: EACCES (Permission denied)

na linii OutputStream myOutput = new FileOutputStream(outFileName);

Sprawdziłem root i spróbowałem android.permission.WRITE_EXTERNAL_STORAGE.

Jak mogę rozwiązać ten problem?

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();
}
Mert
źródło
Miałem ten sam problem na tablecie z Androidem, ale moja sytuacja może być wyjątkowa, dlatego w komentarzu zgłaszam swoje rozwiązanie. Błąd wystąpił, gdy aplikacja próbowała uzyskać dostęp do katalogu / danych / danych / mojej aplikacji / foo, która zawierała ponad 50 plików xml. Aplikacja nie wyczyściła folderu z powodu błędu. Po usunięciu niektórych starych plików błąd zniknął. Nie wiem dlaczego. Może to być problem z ogólnym urządzeniem z Androidem.
Hong
To rozwiązało mnie: stackoverflow.com/questions/33666071/...
partho

Odpowiedzi:

236

Miałem ten sam problem ... To <uses-permissionbyło w złym miejscu. To prawda:

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

uses-permissionTag musi być poza applicationznacznikiem.

użytkownik462990
źródło
2
Chodzi o
3
<uses-permission>Pojawia się ostrzeżenie: „ tag pojawia się po <application>tagu”
mr5
11
OSTRZEŻENIE W Androidzie 4.4.4 nie używaj tego parametru android:maxSdkVersion="18". To generowało ten wyjątek
guisantogui
1
To uprawnienie jest egzekwowane od poziomu API 19. Przed poziomem API 19, to uprawnienie nie jest egzekwowane, a wszystkie aplikacje nadal mają dostęp do odczytu z pamięci zewnętrznej.
Zar E Ahmer
1
używam API lvl 15, otrzymuję błąd podczas próby przeniesienia pliku na pamięć USB OTG
Ravi Mehta
330

W przypadku API 23+ musisz poprosić o uprawnienia do odczytu / zapisu, nawet jeśli są już w twoim manifeście.

// 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" />

Aby uzyskać oficjalną dokumentację dotyczącą żądania uprawnień dla interfejsu API 23+, sprawdź https://developer.android.com/training/permissions/requesting.html

Justin Fiedler
źródło
13
Aby to wyjaśnić, działanie musi obsłużyć odpowiedź na żądanie uprawnień do działania. Więcej informacji znajdziesz na stronie developer.android.com/training/permissions/ ...
kldavis4
Przydatny link z wyjaśnieniem i przykładami tutaj inthecheesefactory.com/blog/…
Paul Alexander
1
czy to nie jest złe? w odniesieniu do doświadczenia użytkownika.
M. Usman Khan,
5
Ale gdzie go używam? na przykład, jeśli chcę zrobić zdjęcie, czy muszę uruchomić VerifyStoragePermissions przed startActivityForResult, czy w onActivityResult? to naprawdę mnie dezorientuje.
Kiwi Lee,
3
Dzięki temu rozwiązujesz mój problem. tylko uwaga: jeśli ktoś nie może rozwiązać „Manifest.permission”, wystarczy zaimportować „import android.Manifest”.
Oubaida AlQuraan
166

Google ma nową funkcję w Androidzie Q : filtrowany widok pamięci zewnętrznej. Szybkim rozwiązaniem jest dodanie tego kodu w pliku AndroidManifest.xml:

<manifest ... >
    <!-- This attribute is "false" by default on apps targeting Android Q. -->
    <application android:requestLegacyExternalStorage="true" ... >
     ...
    </application>
</manifest>

Możesz przeczytać więcej na ten temat tutaj: https://developer.android.com/training/data-storage/compatibility

Uriel Frankel
źródło
@Billy zauważyłem, że dzieje się to tylko na urządzeniach z interfejsem API 29. Więc szukałem zmian w dostawcy plików
Uriel Frankel
W końcu otrzymałem cloudtestingscreenshotter_lib.aar do pracy z tą linią dodaną do manifestu androidTest, bardzo dziękuję za to znalezisko.
bko
6
Panie, zaoszczędziłeś mi dużo czasu. Wiele rzeczy stało się problemem dla programisty w Q. Myślę, że ta odpowiedź powinna być opublikowana jako osobne pytanie i zasługuje na więcej głosów pozytywnych.
sanjeev
Chciałbym przeczytać więcej o tej miłej sztuczce czarnej magii, ale niestety link zwraca błąd 404 ... W każdym razie dzięki
SadSido
daje ostrzeżenie, android:requestLegacyExternalStorage="true"że nie złamie niższych wersji ryt? @UrielFrankel
Santanu Sur
58

Zauważyłem to raz podczas uruchamiania aplikacji w emulatorze. W ustawieniach emulatora należy poprawnie określić rozmiar pamięci zewnętrznej („Karta SD”). Domyślnie pole „pamięć zewnętrzna” jest puste, co prawdopodobnie oznacza, że ​​nie ma takiego urządzenia, a EACCES jest wyrzucany, nawet jeśli w manifeście są przyznane uprawnienia.

Audrius Meskauskas
źródło
51

Oprócz wszystkich odpowiedzi upewnij się, że nie używasz telefonu jako pamięci USB.

Miałem ten sam problem w HTC Sensation w włączonym trybie pamięci USB. Nadal mogę debugować / uruchamiać aplikację, ale nie mogę zapisać w pamięci zewnętrznej.

Jan
źródło
Dzięki człowieku, mimo że poprosiłem użytkownika o uprawnienia w czasie wykonywania. Ten błąd wystąpił w emulatorze.
Sharp Edge
1
Po podłączeniu urządzenia Samsung Galaxy S6 najpierw daje opcję „Zezwól na dostęp do danych urządzenia” za pomocą „DENY” lub „ALLOW”, a także z paska powiadomień dostaję opcję Użyj USB dla 1. MTP 2. PTP 3. MIDI Urządzenia 4. Ładowanie. Który wybrać?
testingh
34

Dodaj android: requestLegacyExternalStorage = "true" na Android Oczywisty To pracował z Androidem 10 (Q) w SDK 29+
lub po migracji 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
źródło
Wow działa idealnie, to była odpowiedź, której szukałem, świetnie, dziękuję @rhaldar, uratowałeś mi dzień
Ayush Katuwal
29

Mój problem dotyczył „TargetApi (23)”, która jest potrzebna, jeśli minSdkVersion ma poniżej 23 lat.

Mam więc pozwolenie na żądanie za pomocą następującego fragmentu kodu

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();
    }
}
Piroxiljin
źródło
28

Rozwiązanie dla Androida Q :

<application ...
    android:requestLegacyExternalStorage="true" ... >
mubin986
źródło
Uratowałeś mi dzień. Zezwolenie zostało udzielone, ale Glide nie może odczytać obrazów, dopóki tego nie ustawię.
leegor
Uwaga: Android 11 całkowicie usunie dostęp do starszej wersji w sierpniu 2020 r., Więc lepiej zaktualizuj dostęp do plików, aby korzystać z Storage Access Framework (SAF) dla swoich aplikacji
dimib
16

Doświadczam tego samego. Znalazłem to, że jeśli przejdziesz do Ustawienia -> Menedżer aplikacji -> Twoja aplikacja -> Uprawnienia -> Włącz przechowywanie , rozwiąże to problem.

Atul Kaushik
źródło
1
Nie mogę znaleźć tej sekcji?
Evan Sevy
13

Okazało się, że to był głupi błąd, ponieważ mój telefon był nadal podłączony do komputera stacjonarnego i nie zdawałem sobie z tego sprawy.

Musiałem więc wyłączyć połączenie USB i wszystko działało dobrze.

Tobias Reich
źródło
pracował również dla mnie. Ale dlaczego to działa? jaka różnica nie powoduje podłączenia USB do komputera.
user13107
Dobre pytanie. Nigdy więcej tego nie badałem. Domyślam się, że jest blokada zapisu z systemu w momencie podłączenia urządzenia (więc może emulować urządzenie USB na twoim komputerze). Być może ma to na celu uniknięcie niespójności danych. Nie jestem pewien.
Tobias Reich,
Znalazłem przyczynę tutaj stackoverflow.com/questions/7396757/... zobacz także moją odpowiedź stackoverflow.com/a/43863548/1729501
użytkownik13107
13

Miałem ten sam problem na Samsungu Galaxy Note 3 z systemem CM 12.1. Problemem było to, że miałem

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

i musiałem go użyć do robienia i przechowywania zdjęć użytkowników. Gdy próbowałem załadować te same zdjęcia w ImageLoader, dostałem (Permission denied)błąd. Rozwiązaniem było jawne dodanie

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

ponieważ powyższe uprawnienie ogranicza jedynie uprawnienie do zapisu do wersji API 18, a wraz z nim uprawnienie do odczytu.

Zoo
źródło
Nie pomogło mi! Warto spróbować! Dzięki.
Sakiboy
9

Oprócz wszystkich odpowiedzi, jeśli klienci używają Androida 6.0, Android dodał nowy model uprawnień dla (Marshmallow).

Sztuczka: jeśli celujesz w wersję 22 lub niższą, aplikacja zażąda wszystkich uprawnień w czasie instalacji, tak jak na każdym urządzeniu z systemem operacyjnym poniżej Marshmallow. Jeśli próbujesz na emulatorze, począwszy od Androida 6.0, musisz wyraźnie przejść do ustawień-> aplikacje-> YOURAPP -> uprawnienia i zmienić uprawnienia, jeśli je nadałeś.

Nourdine Alouane
źródło
2
Niewiarygodne, spędziłem 2 dni próbując to rozgryźć. Za każdym razem, gdy czuję, że wszystko działa płynnie na Androidzie, dzieje się coś takiego.
Jaime Ivan Cervantes,
7

Dziwnie po umieszczeniu ukośnika „/” przed nowym plikiem mój problem został rozwiązany. Zmieniłem to:

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

do tego:

File myFile= new File(Environment.getExternalStorageDirectory() + "/newFile");
Darush
źródło
1
Nic dziwnego tutaj. W pierwszym wierszu próbujesz utworzyć plik w tym samym katalogu, co ten, który zawiera katalog pamięci zewnętrznej. tj. /storage/.../somethingnewfile zamiast /storage/.../something/newfile
Stéphane
@ Stéphane Sam błąd jest dziwny, jeśli spojrzysz na szeroki zakres odpowiedzi.
Darush
3
Prawidłowym sposobem na to jest użycie cosntructor File (reż, plik)
Nick Cardoso
@NickCardoso Możesz także użyć pliku (nazwa ścieżki ciągu). Wygląda na to, że nie rozumiesz tutaj. Pytanie nie dotyczy sposobu korzystania z klasy File. Zakres odpowiedzi w tym wątku pokazuje, jak mylący jest ten błąd i jak wiele możliwych sposobów jego rozwiązania. W moim przypadku błędem był brakujący ukośnik. Niektóre osoby uznały to za przydatne. Na pewno możesz użyć własnej metody dostępu do pliku. Śmiało i opublikuj swoją odpowiedź. Może rozwiązać czyjś problem.
Darush
Nie rozumiesz sensu. Jeśli użyjesz poprawnego konstruktora, twój hack nie będzie wymagany. Mój komentarz został dodany, aby mógł pomóc przyszłym czytelnikom wprowadzonym w błąd przez twój błąd. To nie była osobista krytyka i nie potrzebowałem odpowiedzi
Nick Cardoso
6

Miałem ten sam problem i żadna z sugestii nie pomogła. Ale znalazłem interesujący powód, na fizycznym urządzeniu Galaxy Tab .

Gdy pamięć USB jest włączona, uprawnienia do odczytu i zapisu w pamięci zewnętrznej nie mają żadnego wpływu. Wyłącz pamięć USB, a przy odpowiednich uprawnieniach problem zostanie rozwiązany.

Hamlet Kraskian
źródło
2
Cholera, spędziłem 3 godziny na pracy. Dodatkowo musiałem zrestartować urządzenie i zadziałało. Dziękuję bardzo
crgarridos
5

Spodziewałbym się, że wszystko poniżej /datanależy do „pamięci wewnętrznej”. Powinieneś jednak móc pisać /sdcard.

piekarnik
źródło
5
Próbowałem także <używa-uprawnień android: nazwa = "android.permission.WRITE_INTERNAL_STORAGE" />. wciąż to samo.
Mert
1
Partycja / data jest zazwyczaj chroniona przed zapisem dla zwykłych użytkowników (innych niż root), którzy próbują uzyskać dostęp do plików. W przypadku pamięci wewnętrznej istnieją specjalne metody, aby to zrobić, zwłaszcza jeśli chcesz uzyskać dostęp do baz danych. Do strony programistów Androida powinien pomóc w tej sprawie.
piekarnik
5

Zmień właściwość uprawnień w swojej /system/etc/permission/platform.xml
i grupie, o której mowa, jak poniżej.

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">
    <group android:gid="sdcard_rw" />
    <group android:gid="media_rw" />    
</uses-permission>
Prabakaran
źródło
Platform.xml jest zablokowany od razu, próbując tego za pomocą powłoki adb, ale potrzebuję dowolnego skryptu ADB, który pozwoli mi użyć mod.
John
Zawieść. Umieść moje urządzenie w pętli rozruchowej.
Tobse,
5

Miałem ten sam błąd, gdy próbowałem zapisać obraz w folderze DCIM / camera na Galaxy S5 (Android 6.0.1) i zorientowałem się, że tylko ten folder jest ograniczony. Mógłbym po prostu pisać w DCIM / dowolnym folderze, ale nie w aparacie. Powinno to być ograniczenie / dostosowanie oparte na marce.

Mahdi Mehrizi
źródło
4

Gdy aplikacja należy do aplikacji systemowej, nie może uzyskać dostępu do karty SD.

będzie
źródło
4

pamiętaj, że nawet jeśli ustawisz wszystkie poprawne uprawnienia w manifeście: Jedynym miejscem, w którym aplikacje innych firm mogą pisać na twojej karcie zewnętrznej, są „własne katalogi” (tj. / sdcard / Android / data /) próbujące pisać do gdziekolwiek indziej: otrzymasz wyjątek: EACCES (odmowa zezwolenia)

Elad
źródło
3

Może odpowiedź brzmi:

na interfejsie API> = 23, jeśli zainstalujesz aplikację (aplikacja nie jest aplikacją systemową), powinieneś sprawdzić uprawnienia do przechowywania w „Ustawieniach - aplikacje”, dla każdej aplikacji jest lista uprawnień! Powinieneś to sprawdzić! próbować

Jason Zhu
źródło
3

W moim przypadku korzystałem z biblioteki wyboru plików, która zwróciła ścieżkę do pamięci zewnętrznej, ale zaczęła się od /root/. I nawet z uprawnieniem WRITE_EXTERNAL_STORAGE udzielonym w czasie wykonywania nadal mam błąd EACCES (odmowa zezwolenia) .
Użyj więc, Environment.getExternalStorageDirectory()aby uzyskać prawidłową ścieżkę do pamięci zewnętrznej.

Przykład:
Nie można pisać: /root/storage/emulated/0/newfile.txt
Można pisać: /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;
}

Wyjście 1:

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

Wyjście 2:

externalStorageWritable: true
filePath: /storage/emulated/0/newfile.txt
isFile: true
usableSpace: 1331007488
vovahost
źródło
Miałem dokładnie ten sam problem. Usunięcie rootczęści ze ścieżki rozwiązało mój problem.
xabush
3
Environment.getExternalStoragePublicDirectory();

Podczas korzystania z tej przestarzałej metody od Androida 29 pojawi się ten sam błąd:

java.io.FileNotFoundException: open failed: EACCES (Permission denied)

Rozdzielczość tutaj:

getExternalStoragePublicDirectory jest przestarzałe w Androidzie Q

użytkownik2965003
źródło
3

Dla każdego, kto przychodzi tutaj z wyników wyszukiwania i celuje w Androida 10: Android 10 (API 29) zmienia niektóre uprawnienia związane z pamięcią masową.

Rozwiązałem ten problem, zastępując moje poprzednie wystąpienia Environment.getExternalStorageDirectory()(które są przestarzałe API 29) context.getExternalFilesDir(null).

Pamiętaj, że context.getExternalFilesDir(type)może zwrócić wartość null, jeśli lokalizacja pamięci nie jest dostępna, więc upewnij się, że sprawdzasz, czy masz uprawnienia zewnętrzne.

Przeczytaj więcej tutaj .

jacoballenwood
źródło
2

Tworzę folder w katalogu / data / w moim pliku init.rc (chowając się wokół aosp na Nexusie 7) i miałem dokładnie ten problem.

Okazało się, że udzielenie uprawnienia do folderu rw (666) nie było wystarczające i musiał to być rwx (777), wtedy wszystko działało!

pas ruchu
źródło
2

Egzekwowanie uprawnień do przechowywania danych po wersji 6.0 można ominąć, jeśli masz zrootowane urządzenie za pomocą następujących poleceń adb:

root@msm8996:/ # getenforce
getenforce
Enforcing
root@msm8996:/ # setenforce 0
setenforce 0
root@msm8996:/ # getenforce
getenforce
Permissive
Zakir
źródło
1

Dodaj zezwolenie w manifeście.

<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"/>
Harman Khera
źródło
3
Brak pozwoleniaandroid.permission.READ_INTERNAL_STORAGE
Ryan R
0

Miałem ten sam problem (API> = 23).

Rozwiązanie https://stackoverflow.com/a/13569364/1729501 działało dla mnie, ale nie było praktyczne odłączanie aplikacji do debugowania.

moim rozwiązaniem było zainstalowanie odpowiedniego sterownika urządzenia adb w systemie Windows. Sterownik USB Google nie działał na moim urządzeniu.

KROK 1: Pobierz sterowniki adb dla swojej marki urządzenia.

KROK 2: Przejdź do menedżera urządzeń -> inne urządzenia -> wyszukaj wpisy ze słowem „adb” -> wybierz Aktualizuj sterownik -> podaj lokalizację w kroku 1

użytkownik13107
źródło
0

po dodaniu pozwolenia rozwiązałem mój problem

<uses-permission android:name="android.permission.INTERNET"/>
Sai Gopi N.
źródło
0

Dodaj zależności stopni

implementation 'com.karumi:dexter:4.2.0'

Dodaj poniższy kod do swojej głównej działalności.

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();
    }
ethemsulan
źródło
0

W moim przypadku błąd pojawiał się na linii

      target.createNewFile();

ponieważ nie mogłem utworzyć nowego pliku na karcie SD, musiałem zastosować podejście DocumentFile.

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

W przypadku powyższego pytania problem można rozwiązać za pomocą tego podejścia,

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

Zobacz także ten wątek. Jak korzystać z nowego interfejsu API dostępu do karty SD przedstawionego dla Androida 5.0 (Lollipop)?

Tarasantan
źródło