Excepción 'error de apertura: EACCES (permiso denegado)' en Android

298

estoy obteniendo

abierto fallido: EACCES (Permission denied)

en la línea OutputStream myOutput = new FileOutputStream(outFileName);

Revisé la raíz y lo intenté android.permission.WRITE_EXTERNAL_STORAGE.

¿Como puedo solucionar este problema?

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
fuente
Tuve el mismo problema en una tableta Android, pero mi situación puede ser única, así que informo mi solución aquí en un comentario. El error ocurrió cuando la aplicación intentó acceder al directorio / data / data / myapp / foo que tenía más de 50 archivos xml. La aplicación no limpió la carpeta debido a un error. Después de que se eliminaron algunos archivos antiguos, el error desapareció. No se por que. Podría ser un problema del dispositivo Android genérico.
Hong
Esto me resolvió: stackoverflow.com/questions/33666071/…
partho

Respuestas:

236

Tuve el mismo problema ... <uses-permissionEstaba en el lugar equivocado. Esto es correcto:

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

La uses-permissionetiqueta debe estar fuera de la applicationetiqueta.

usuario462990
fuente
2
es que las necesidades usos permiso para estar fuera de la aplicación
user462990
3
Recibo una advertencia: "la <uses-permission>etiqueta aparece después de la <application>etiqueta"
mr5
11
ADVERTENCIA En Android 4.4.4 no use el parámetro android:maxSdkVersion="18". Estaba generando esta excepción
guisantogui
1
Este permiso se aplica a partir del nivel de API 19. Antes del nivel de API 19, este permiso no se aplica y todas las aplicaciones aún tienen acceso para leer desde el almacenamiento externo.
Zar E Ahmer
1
estoy usando API lvl 15, obtengo un error al intentar mover el archivo a una memoria USB OTG
Ravi Mehta
330

Para API 23+, debe solicitar los permisos de lectura / escritura incluso si ya están en su manifiesto.

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

Para obtener documentación oficial sobre cómo solicitar permisos para API 23+, consulte https://developer.android.com/training/permissions/requesting.html

Justin Fiedler
fuente
13
Solo para aclarar, para que esto funcione, la actividad debe manejar la respuesta de solicitud de permisos de actividad. Visita developer.android.com/training/permissions/… para más detalles.
kldavis4
Enlace práctico con explicación y ejemplos aquí en thecheesefactory.com/blog/…
Paul Alexander
1
¿No es esto algo malo? con respecto a la experiencia del usuario.
M. Usman Khan
55
¿Pero dónde lo uso? por ejemplo, si quiero tomar una foto, ¿tengo que ejecutar verifiqueServiciosPermisos antes de comenzarActivityForResult o en onActivityResult? Realmente me confunde.
Kiwi Lee
3
Gracias, esto resuelve mi problema. solo una nota: si alguien no puede resolver "Manifest.permission" solo necesita importar "import android.Manifest".
Oubaida AlQuraan
169

Google tiene una nueva función en Android Q : vista filtrada para almacenamiento externo. Una solución rápida para eso es agregar este código en el archivo AndroidManifest.xml:

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

Puede leer más sobre esto aquí: https://developer.android.com/training/data-storage/compatibility

Uriel Frankel
fuente
@Billy noté que solo sucede en dispositivos con la API 29. Así que busqué cambios en el proveedor de archivos
Uriel Frankel el
Finalmente conseguí que cloudtestingscreenshotter_lib.aar funcionara con esta línea agregada al manifiesto androidTest, muchas gracias por este hallazgo.
bko
66
Usted señor, me ahorró mucho tiempo. Muchas cosas se han convertido en una molestia para un desarrollador en Q. Creo que esta respuesta debería publicarse como una pregunta separada y merece más votos a favor.
sanjeev
Me gustaría leer más sobre este pequeño y agradable truco de magia negra, pero desafortunadamente el enlace devuelve un error 404 ... Gracias de todos modos
SadSido
está dando una advertencia de que android:requestLegacyExternalStorage="true"esto no romperá las versiones inferiores ryt? @UrielFrankel
Santanu Sur
58

Lo he observado una vez cuando ejecuto la aplicación dentro del emulador. En la configuración del emulador, debe especificar el tamaño del almacenamiento externo ("Tarjeta SD") correctamente. De manera predeterminada, el campo "almacenamiento externo" está vacío, y eso probablemente significa que no existe tal dispositivo y que se lanza EACCES incluso si se otorgan permisos en el manifiesto.

Audrius Meskauskas
fuente
51

Además de todas las respuestas, asegúrese de no estar usando su teléfono como almacenamiento USB.

Estaba teniendo el mismo problema en HTC Sensation en el modo de almacenamiento USB habilitado. Todavía puedo depurar / ejecutar la aplicación, pero no puedo guardar en el almacenamiento externo.

Juan
fuente
Gracias hombre, a pesar de que había solicitado permisos del usuario en tiempo de ejecución. Este error ocurrió en el emulador.
Sharp Edge
1
Cuando conecto el dispositivo Samsung Galaxy S6, primero aparece la opción "Permitir acceso a los datos del dispositivo" con "NEGAR" o "PERMITIR" y también desde la barra de notificaciones obtengo una opción Usar USB para 1. MTP 2. PTP 3. MIDI Dispositivos 4. Carga. ¿Cuál elegir?
testingingh
34

Añadir androide: requestLegacyExternalStorage = "true" a la de Android manifestarla trabajado con Android 10 (Q) en el SDK de 29+
o Después de migrar 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
fuente
Wow funciona perfectamente, esa fue la respuesta que estaba buscando, genial, gracias @rhaldar, me salvaste el día
Ayush Katuwal
29

Mi problema fue con "TargetApi (23)", que es necesario si su minSdkVersion es inferior a 23.

Entonces, solicito permiso con el siguiente fragmento

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
fuente
28

Solución para Android Q :

<application ...
    android:requestLegacyExternalStorage="true" ... >
mubin986
fuente
Me has salvado el día. Se otorga el permiso, pero Glide no puede leer imágenes hasta que establezca esto.
leegor
Precaución: Android 11 eliminará completamente el acceso legado en agosto de 2020, el acceso a archivos de actualización así que es mejor utilizar el almacenamiento Marco de Acceso (SAF) para sus aplicaciones
dimib
16

Estoy experimentando lo mismo. Lo que encontré es que si vas a Configuración -> Administrador de aplicaciones -> Tu aplicación -> Permisos -> Habilitar almacenamiento , resuelve el problema.

Atul Kaushik
fuente
1
¿No puedo encontrar esta sección?
Evan Sevy
13

Resultó que fue un error estúpido ya que todavía tenía mi teléfono conectado a la PC de escritorio y no me di cuenta de esto.

Así que tuve que apagar la conexión USB y todo funcionó bien.

Tobias Reich
fuente
Me funcionó a mi también. ¿Pero por qué funciona? ¿Qué diferencia no hace la conexión de USB a PC?
user13107
Buena pregunta. Nunca investigé esto más a fondo. Supongo que hay un bloqueo de escritura del sistema en el momento en que conecta el dispositivo (por lo que puede emular un dispositivo usb en su computadora). Quizás esto sea para evitar datos inconsistentes. Aunque no estoy seguro.
Tobias Reich
Encontré la razón aquí stackoverflow.com/questions/7396757/… también vea mi respuesta stackoverflow.com/a/43863548/1729501
user13107
13

Tuve el mismo problema en Samsung Galaxy Note 3, ejecutando CM 12.1. El problema para mí fue que tenía

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

y tuve que usarlo para tomar y almacenar fotos de usuarios. Cuando intenté cargar esas mismas fotos en ImageLoader, recibí el (Permission denied)error. La solución fue agregar explícitamente

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

dado que el permiso anterior solo limita el permiso de escritura hasta la versión 18 de API, y con él el permiso de lectura.

ZooS
fuente
No me ayudo! Vale la pena intentarlo! Gracias.
Sakiboy
9

Además de todas las respuestas, si los clientes están usando Android 6.0, Android agregó un nuevo modelo de permiso para (Marshmallow).

Truco: si está apuntando a la versión 22 o inferior, su aplicación solicitará todos los permisos en el momento de la instalación como lo haría en cualquier dispositivo que ejecute un sistema operativo por debajo de Marshmallow. Si está probando el emulador, a partir de Android 6.0 en adelante, debe ir explícitamente a la configuración-> aplicaciones-> YOURAPP -> permisos y cambiar el permiso si ha otorgado alguno.

Nourdine Alouane
fuente
2
Increíble, pasé 2 días tratando de resolver esto. Cada vez que siento que las cosas funcionan sin problemas en Android, ocurre algo como esto.
Jaime Ivan Cervantes
7

Extrañamente después de poner una barra "/" antes de mi nuevo archivo, mi problema se resolvió. Cambié esto:

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

a esto:

File myFile= new File(Environment.getExternalStorageDirectory() + "/newFile");
Darush
fuente
1
Nada extraño aquí. Con la primera línea está intentando crear un archivo en el mismo directorio que el que contiene su directorio de almacenamiento externo. ie /storage/.../somethingnewfile en lugar de /storage/.../something/newfile
Stéphane
@ Stéphane El error en sí mismo es extraño si nos fijamos en la amplia gama de respuestas.
Darush
3
La forma correcta de hacer esto es usar el constructor de archivos (dir, file)
Nick Cardoso
@NickCardoso También puede usar File (String pathname). Parece que no estás entendiendo el punto aquí. La pregunta no es acerca de cómo usar la clase File. El rango de respuestas en este hilo muestra cuán engañoso es este error y cuántas formas posibles de resolverlo. En mi caso, el error fue la barra oblicua faltante. Algunas personas lo han encontrado útil. Seguro que puedes usar tu propio método para acceder a un archivo. Anímate y publica tu respuesta. Puede resolver el problema de alguien.
Darush
No estás entendiendo el punto. Si usa el constructor correcto, entonces su pirateo no es necesario. Se agregó mi comentario para que pueda ayudar a cualquier futuro lector engañado por su error. No fue una crítica personal y no necesité una respuesta
Nick Cardoso
6

Tuve el mismo problema y ninguna de las sugerencias me ayudó. Pero encontré una razón interesante para eso, en un dispositivo físico, Galaxy Tab .

Cuando el almacenamiento USB está activado, los permisos de lectura y escritura de almacenamiento externo no tienen ningún efecto. Simplemente apague el almacenamiento USB, y con los permisos correctos, tendrá el problema resuelto.

Hamlet Kraskian
fuente
2
Maldita sea, solo pasé como 3 horas trabajando. Además, tuve que reiniciar el dispositivo y funcionó. Muchas gracias
crgarridos
5

Esperaría que todo lo siguiente /datapertenezca al "almacenamiento interno". Sin embargo, deberías poder escribir /sdcard.

horno
fuente
55
Intenté <uses-permission android: name = "android.permission.WRITE_INTERNAL_STORAGE" /> también. todavía lo mismo.
Mert
1
La partición / data generalmente está protegida contra escritura para los usuarios normales (no root) que intentan acceder al archivo ordinario. Para el almacenamiento interno, existen métodos especializados para hacerlo, especialmente si desea acceder a las bases de datos. Las páginas de desarrolladores de Android deberían ayudarte en este tema.
ovenror
5

Cambie una propiedad de permiso en su /system/etc/permission/platform.xml
grupo y debe mencionarlo como a continuación.

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">
    <group android:gid="sdcard_rw" />
    <group android:gid="media_rw" />    
</uses-permission>
Prabakaran
fuente
platform.xml está bloqueado directamente, intentando esto a través de adb shell pero necesita cualquier script que ADB me permita usar para el mod.
John
Fallar. Poner mi dispositivo en un bucle de arranque.
Tobse
5

Tuve el mismo error cuando intentaba escribir una imagen en la carpeta DCIM / camera en Galaxy S5 (android 6.0.1) y descubrí que solo esta carpeta está restringida. Simplemente podría escribir en DCIM / cualquier carpeta pero no en la cámara. Esto debería ser una restricción / personalización basada en la marca.

Mahdi Mehrizi
fuente
4

Cuando su aplicación pertenece a la aplicación del sistema, no puede acceder a la tarjeta SD.

será
fuente
4

tenga en cuenta que incluso si establece todos los permisos correctos en el manifiesto: el único lugar donde las aplicaciones de terceros pueden escribir en su tarjeta externa es "sus propios directorios" (es decir, / sdcard / Android / data /) que intentan escribir en en cualquier otro lugar: obtendrá una excepción: EACCES (permiso denegado)

Elad
fuente
3

Quizás la respuesta es esta:

en la API> = 23 dispositivos, si instala la aplicación (la aplicación no es la aplicación del sistema), debe verificar el permiso de almacenamiento en "Configuración - aplicaciones", hay una lista de permisos para cada aplicación, ¡debe verificarla! tratar

Jason Zhu
fuente
3

En mi caso, estaba usando una biblioteca de selección de archivos que devolvió la ruta al almacenamiento externo pero comenzó /root/. E incluso con el permiso WRITE_EXTERNAL_STORAGE otorgado en tiempo de ejecución, todavía recibí el error EACCES (permiso denegado) .
Así que use Environment.getExternalStorageDirectory()para obtener la ruta correcta al almacenamiento externo.

Ejemplo:
no se puede escribir: se /root/storage/emulated/0/newfile.txt
puede escribir: /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;
}

Salida 1:

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

Salida 2:

externalStorageWritable: true
filePath: /storage/emulated/0/newfile.txt
isFile: true
usableSpace: 1331007488
vovahost
fuente
Estaba teniendo el mismo problema exacto. Eliminar la rootparte de la ruta resolvió mi problema.
xabush
3
Environment.getExternalStoragePublicDirectory();

Al utilizar este método obsoleto desde Android 29 en adelante, recibirá el mismo error:

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

Resolución aquí:

getExternalStoragePublicDirectory en desuso en Android Q

usuario2965003
fuente
3

Para cualquier persona que venga de los resultados de búsqueda y apunte a Android 10: Android 10 (API 29) cambia algunos permisos relacionados con el almacenamiento.

Solucioné el problema cuando reemplacé mis instancias anteriores de Environment.getExternalStorageDirectory()(que está en desuso con API 29) por context.getExternalFilesDir(null).

Tenga en cuenta que context.getExternalFilesDir(type) puede devolver nulo si la ubicación de almacenamiento no está disponible, así que asegúrese de verificarlo cada vez que verifique si tiene permisos externos.

Lee más aquí .

jacoballenwood
fuente
2

Estoy creando una carpeta en / data / en mi init.rc (jugando con el aosp en Nexus 7) y tuve exactamente este problema.

Resultó que darle permiso a la carpeta rw (666) no era suficiente y tenía que ser rwx (777) ¡entonces todo funcionó!

carril
fuente
2

La aplicación posterior 6.0 de los permisos de almacenamiento se puede omitir si tiene un dispositivo rooteado a través de estos comandos adb:

root@msm8996:/ # getenforce
getenforce
Enforcing
root@msm8996:/ # setenforce 0
setenforce 0
root@msm8996:/ # getenforce
getenforce
Permissive
Zakir
fuente
1

Agregar permiso en manifiesto.

<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
fuente
3
No hay permisoandroid.permission.READ_INTERNAL_STORAGE
Ryan R
0

Tuve el mismo problema (API> = 23).

La solución https://stackoverflow.com/a/13569364/1729501 funcionó para mí, pero no era práctico desconectar la aplicación para la depuración.

mi solución fue instalar el controlador de dispositivo adb adecuado en Windows. El controlador USB de google no funcionó para mi dispositivo.

PASO 1: descargue los controladores adb para la marca de su dispositivo.

PASO 2: Vaya al administrador de dispositivos -> otros dispositivos -> busque entradas con la palabra "adb" -> seleccione Actualizar controlador -> indique la ubicación en el paso 1

usuario13107
fuente
0

después de agregar permiso resolvió mi problema

<uses-permission android:name="android.permission.INTERNET"/>
Sai Gopi N
fuente
0

Agregar dependencias de gradle

implementation 'com.karumi:dexter:4.2.0'

Agregue el siguiente código en su actividad principal.

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();
    }
etemsulano
fuente
0

En mi caso, el error aparecía en la línea

      target.createNewFile();

Como no podía crear un nuevo archivo en la tarjeta SD, tuve que usar el enfoque DocumentFile.

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

Para la pregunta anterior, el problema puede resolverse con este enfoque,

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

Vea este hilo también, ¿Cómo usar la nueva API de acceso a la tarjeta SD presentada para Android 5.0 (Lollipop)?

Tarasantan
fuente