Manera universal de escribir en la tarjeta SD externa en Android

En mi aplicación necesito almacenar muchas imágenes en el almacenamiento del dispositivo. Tales imágenes tienden a cumplir el almacenamiento del dispositivo y quiero permitir a los usuarios ser capaces de elegir la tarjeta SD externa como carpeta de destino.

He leído en todas partes que Android no permite a los usuarios escribir a la tarjeta SD externa, por tarjeta SD Me refiero a la tarjeta externa y montable SD y no el almacenamiento externo , pero las aplicaciones de gestor de archivos se las arreglan para escribir en SD externo en todas las versiones de Android.

¿Cuál es la mejor manera de conceder acceso de lectura / escritura a la tarjeta SD externa en diferentes niveles de api (Pre-KitKat, KitKat, Lollipop +)?

Actualización 1

Intenté el método 1 de la respuesta de Doomknight, sin ninguna utilidad: Como usted puede ver que estoy comprobando para los permisos en tiempo de ejecución antes de intentar escribir en SD:

HashSet<String> extDirs = getStorageDirectories(); for(String dir: extDirs) { Log.e("SD",dir); File f = new File(new File(dir),"TEST.TXT"); try { if(ActivityCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE)==PackageManager.PERMISSION_GRANTED) { f.createNewFile(); } } catch (IOException e) { e.printStackTrace(); } } 

Pero me sale un error de acceso, probado en dos dispositivos diferentes: HTC10 y Shield K1

 10-22 14:52:57.329 30280-30280/? E/SD: /mnt/media_rw/F38E-14F8 10-22 14:52:57.329 30280-30280/? W/System.err: java.io.IOException: open failed: EACCES (Permission denied) 10-22 14:52:57.329 30280-30280/? W/System.err: at java.io.File.createNewFile(File.java:939) 10-22 14:52:57.329 30280-30280/? W/System.err: at com.myapp.activities.TestActivity.onResume(TestActivity.java:167) 10-22 14:52:57.329 30280-30280/? W/System.err: at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1326) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.Activity.performResume(Activity.java:6338) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3336) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3384) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2574) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.access$900(ActivityThread.java:150) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1399) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.os.Handler.dispatchMessage(Handler.java:102) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.os.Looper.loop(Looper.java:168) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5885) 10-22 14:52:57.330 30280-30280/? W/System.err: at java.lang.reflect.Method.invoke(Native Method) 10-22 14:52:57.330 30280-30280/? W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:819) 10-22 14:52:57.330 30280-30280/? W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:709) 10-22 14:52:57.330 30280-30280/? W/System.err: Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied) 10-22 14:52:57.330 30280-30280/? W/System.err: at libcore.io.Posix.open(Native Method) 10-22 14:52:57.330 30280-30280/? W/System.err: at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186) 10-22 14:52:57.330 30280-30280/? W/System.err: at java.io.File.createNewFile(File.java:932) 10-22 14:52:57.330 30280-30280/? W/System.err: ... 14 more 

6 Solutions collect form web for “Manera universal de escribir en la tarjeta SD externa en Android”

1. Resumen.

No hay forma universal de escribir en la tarjeta SD externa en Android debido a cambios continuos:

  • Pre-KitKat: la plataforma oficial de Android no ha soportado tarjetas SD en absoluto excepto excepciones.

  • KitKat: APIs introducidas que permiten a las aplicaciones acceder a archivos en directorios específicos de aplicaciones en tarjetas SD.

  • Lollipop: agregó API para permitir que las aplicaciones soliciten acceso a carpetas propiedad de otros proveedores.

  • Nougat: proporciona una API simplificada para acceder a directorios de almacenamiento externo comunes.

Puede conceder acceso de lectura / escritura a la tarjeta SD externa en los diferentes niveles de api ( API23 + en tiempo de ejecución ).

Desde KitKat, los permisos no son necesarios si se utilizan directorios específicos de la aplicación, se requiere lo contrario:

Con Kitkat tus posibilidades de una "solución completa" sin enraizamiento son prácticamente cero: el proyecto de Android definitivamente ha arruinado aquí. No hay aplicaciones que tengan acceso completo a la tarjeta SD externa:

  • Gestores de archivos: no puede utilizarlos para administrar su tarjeta SD externa. En la mayoría de las áreas, sólo pueden leer pero no escribir.
  • Aplicaciones de medios: no puede volver a organizar / volver a organizar su colección de medios, ya que esas aplicaciones no pueden escribir en ella.
  • Aplicaciones de oficina: prácticamente lo mismo

El único lugar en el que se permite a las aplicaciones de terceros que escriban en su tarjeta externa son "sus propios directorios" (es decir, /sdcard/Android/data/<package_name_of_the_app> ).

Las únicas maneras de arreglar realmente que requieren el fabricante (algunos de ellos lo arreglaron, por ejemplo Huawei con su actualización de Kitkat para el P6) – o raíz … (la explicación de Izzy continúa aquí)

ContextCompat.getExternalFilesDirs resuelve el problema si no necesita tener acceso a otras carpetas .


2. Acerca de la solución universal.

La historia dice que no hay manera universal de escribir a la tarjeta SD externa, pero continúa …

Este hecho es demostrado por estos ejemplos de configuraciones de almacenamiento externas para dispositivos .

El acceso al almacenamiento externo está protegido por varios permisos de Android. A partir de Android 1.0, el acceso de escritura está protegido con el permiso WRITE_EXTERNAL_STORAGE . A partir de Android 4.1, el acceso de lectura está protegido con el permiso READ_EXTERNAL_STORAGE .

A partir de Android 4.4, el propietario, el grupo y los modos de archivos de los dispositivos de almacenamiento externos ahora se sintetizan en función de la estructura de directorios. Esto permite a las aplicaciones administrar sus directorios específicos de paquetes en el almacenamiento externo sin necesidad de tener el amplio permiso WRITE_EXTERNAL_STORAGE . Por ejemplo, la aplicación con nombre de paquete com.example.foo ahora puede acceder libremente a Android/data/com.example.foo/ en dispositivos de almacenamiento externo sin permisos. Estos permisos sintetizados se realizan envolviendo dispositivos de almacenamiento sin procesar en un daemon FUSE.

Android 6.0 introduce un nuevo modelo de permisos de tiempo de ejecución en el que las aplicaciones solicitan capacidades cuando se necesitan en tiempo de ejecución. Debido a que el nuevo modelo incluye los permisos READ/WRITE_EXTERNAL_STORAGE , la plataforma debe conceder acceso de almacenamiento dinámicamente sin eliminar o reiniciar aplicaciones que ya se READ/WRITE_EXTERNAL_STORAGE ejecutando. Para ello, mantiene tres vistas distintas de todos los dispositivos de almacenamiento montados:

  • / Mnt / runtime / default se muestra a las aplicaciones sin permisos especiales de almacenamiento …
  • / Mnt / runtime / read se muestra a las aplicaciones con READ_EXTERNAL_STORAGE
  • / Mnt / runtime / write se muestra a las aplicaciones con WRITE_EXTERNAL_STORAGE

3. Acerca de su actualización 1.

Yo usaría directorios específicos de la aplicación para evitar el problema de su pregunta actualizada y ContextCompat.getExternalFilesDirs() utilizando la documentación getExternalFilesDir como referencia.

Mejore la heurística para determinar qué representa los medios extraíbles basados ​​en los diferentes niveles de api como android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT

Recuerde que Android 6.0 admite dispositivos de almacenamiento portátil y que las aplicaciones de terceros deben pasar por el Storage Access Framework . Sus dispositivos HTC10 y Shield K1 son probablemente API 23.

Su registro muestra una excepción de permiso denegada que accede a /mnt/media_rw , como esta corrección para API 19+:

 <permission name="android.permission.WRITE_EXTERNAL_STORAGE" > <group gid="sdcard_r" /> <group gid="sdcard_rw" /> <group gid="media_rw" /> // this line is added via root in the link to fix it. </permission> 

Nunca lo intenté así que no puedo compartir el código sino que evitaría el for intentar escribir en todos los directorios vueltos y buscar el mejor directorio disponible del almacenaje para escribir en basado en el espacio restante .

Quizás la alternativa de getStorageDirectories() a tu método de getStorageDirectories() es un buen punto de partida.

ContextCompat.getExternalFilesDirs resuelve el problema si no necesita tener acceso a otras carpetas .


4. Solicitar permisos en manifiesto (Api <23) y en tiempo de ejecución (Api> = 23).

Agregue el siguiente código a su AndroidManifest.xml y lea Obtener acceso a almacenamiento externo

Con el fin de … escribir archivos en el almacenamiento externo, su aplicación debe adquirir … permisos del sistema:

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

Si necesita ambos …, debe solicitar sólo el permiso WRITE_EXTERNAL_STORAGE .

Ignore la siguiente nota debido a errores, pero trate de usar ContextCompat.getExternalFilesDirs() :

Nota: A partir de Android 4.4, estos permisos no son necesarios si estás leyendo o escribiendo sólo archivos privados para tu aplicación. Para más información …, vea guardar los archivos que son app-private .

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

Solicitar permisos en tiempo de ejecución si API nivel 23+ y leer Solicitar permisos en tiempo de ejecución

A partir de Android 6.0 (API nivel 23), los usuarios conceden permisos a las aplicaciones mientras la aplicación se ejecuta, no cuando instalan la aplicación … o actualizar la aplicación … el usuario puede revocar los permisos.

 // Assume thisActivity is the current activity int permissionCheck = ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE); 

5. Antes de KitKat tratar de utilizar Doomsknight método 1, método 2 de lo contrario.

Lea la explicación de Mark Murphy y recomendó a Dianne Hackborn y Dave Smith

  • Hasta Android 4.4, no había soporte oficial para medios extraíbles en Android, a partir de KitKat, el concepto de almacenamiento externo "primario" y "secundario" emerge en la API FMW.
  • Las aplicaciones anteriores sólo se basan en la indexación de MediaStore, se envían con el hardware o se examinan los puntos de montaje y se aplican algunas heurísticas para determinar qué representa los medios extraíbles.
  • Desde Android 4.2, ha habido una solicitud de Google para que los fabricantes de dispositivos bloqueen los medios extraíbles para la seguridad (compatibilidad con varios usuarios) y se añadieron nuevas pruebas en 4.4.
  • Desde KiKat getExternalFilesDirs() y otros métodos se agregaron para devolver una ruta utilizable en todos los volúmenes de almacenamiento disponibles (El primer elemento devuelto es el volumen principal).
  • La siguiente tabla indica lo que un desarrollador podría intentar hacer y cómo responderá KitKat: Introduzca aquí la descripción de la imagen

Antes de KitKat tratar de utilizar el método Doomsknight 1 o leer esta respuesta por Gnathonic o esencial :

 public static HashSet<String> getExternalMounts() { final HashSet<String> out = new HashSet<String>(); String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*"; String s = ""; try { final Process process = new ProcessBuilder().command("mount") .redirectErrorStream(true).start(); process.waitFor(); final InputStream is = process.getInputStream(); final byte[] buffer = new byte[1024]; while (is.read(buffer) != -1) { s = s + new String(buffer); } is.close(); } catch (final Exception e) { e.printStackTrace(); } // parse output final String[] lines = s.split("\n"); for (String line : lines) { if (!line.toLowerCase(Locale.US).contains("asec")) { if (line.matches(reg)) { String[] parts = line.split(" "); for (String part : parts) { if (part.startsWith("/")) if (!part.toLowerCase(Locale.US).contains("vold")) out.add(part); } } } } return out; } 

También lea la explicación de Paolo Rovelli y trate de usar la solución de Jeff Sharkey desde KitKat:

En KitKat ahora hay una API pública para interactuar con estos dispositivos de almacenamiento compartido secundario.

Los nuevos Context.getExternalFilesDirs() y Context.getExternalCacheDirs() pueden devolver varias rutas, incluidos los dispositivos primarios y secundarios.

A continuación, puede iterar sobre ellos y comprobar Environment.getStorageState() y File.getFreeSpace() para determinar el mejor lugar para almacenar sus archivos.

Estos métodos también están disponibles en ContextCompat en la biblioteca support-v4.


6. Lollipop también introdujo cambios y la clase auxiliar DocumentFile .

getStorageState Agregado en la API 19, obsoleto en la API 21, use getExternalStorageState(File)

Aquí hay un gran tutorial para interactuar con el Storage Access Framework en KitKat.

Interactuar con las nuevas API en Lollipop es muy similar (explicación de Jeff Sharkey) .


7. Android 7.0 proporciona una API simplificada para acceder a directorios de almacenamiento externo.

Acceso a directorios con alcance En Android 7.0, las aplicaciones pueden utilizar nuevas API para solicitar acceso a directorios de almacenamiento externo específicos, incluidos directorios de medios extraíbles como tarjetas SD …

Para obtener más información, consulte el curso Acceso al directorio de Scoped .


8. Cambios en Android O.

A partir de Android O , Storage Access Framework permite a los proveedores de documentos personalizados crear descriptores de archivos buscables para archivos que residen en una fuente de datos remota …

Permisos anteriores a Android O , si una aplicación solicitó un permiso en tiempo de ejecución y se concedió el permiso, el sistema también concedió incorrectamente a la aplicación el resto de los permisos que pertenecían al mismo grupo de permisos y que estaban registrados en el manifiesto.

Para aplicaciones orientadas a Android O , este comportamiento se ha corregido. La aplicación se concede sólo los permisos que ha solicitado explícitamente. Sin embargo, una vez que el usuario otorga un permiso a la aplicación, todas las solicitudes posteriores de permisos en ese grupo de permisos se conceden automáticamente.

Por ejemplo, READ_EXTERNAL_STORAGE y WRITE_EXTERNAL_STORAGE


9. Preguntas relacionadas y respuestas recomendadas.

¿Cómo puedo obtener la ruta de la tarjeta SD externa para Android 4.0 y versiones posteriores?

Mkdir () funciona mientras está dentro de almacenamiento flash interno, pero no tarjeta SD?

Diferencia entre getExternalFilesDir y getExternalStorageDirectory ()

¿Por qué getExternalFilesDirs () no funciona en algunos dispositivos?

Cómo utilizar la nueva API de acceso a tarjetas SD presentada para Android 5.0 (Lollipop)

Escribir en una tarjeta SD externa en Android 5.0 o superior

Permiso de escritura de la tarjeta SD de Android mediante SAF (Storage Access Framework)

SAFFAQ: Preguntas frecuentes sobre el Framework de acceso al almacenamiento


10. Bugs y problemas relacionados.

Bug: En Android 6, al usar getExternalFilesDirs, no le permitirá crear nuevos archivos en sus resultados

Escribir en el directorio devuelto por getExternalCacheDir () en Lollipop falla sin permiso de escritura

Creo que hay dos métodos para lograr esto:

MÉTODO 1: ( NO funciona en 6.0 y superiores, debido a cambios de permiso)

He estado usando este método durante años en la versión de muchos dispositivos sin ningún problema. El crédito se debe a la fuente original, ya que no fui yo quien la escribió.

Devolverá todos los medios montados (incluyendo tarjetas de Real SD) en una lista de ubicaciones de directorios de cadenas. Con la lista puede pedir al usuario dónde guardar, etc.

Puede llamarlo con lo siguiente:

  HashSet<String> extDirs = getStorageDirectories(); 

Método:

 /** * Returns all the possible SDCard directories */ public static HashSet<String> getStorageDirectories() { final HashSet<String> out = new HashSet<String>(); String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*"; String s = ""; try { final Process process = new ProcessBuilder().command("mount") .redirectErrorStream(true).start(); process.waitFor(); final InputStream is = process.getInputStream(); final byte[] buffer = new byte[1024]; while (is.read(buffer) != -1) { s = s + new String(buffer); } is.close(); } catch (final Exception e) { e.printStackTrace(); } // parse output final String[] lines = s.split("\n"); for (String line : lines) { if (!line.toLowerCase().contains("asec")) { if (line.matches(reg)) { String[] parts = line.split(" "); for (String part : parts) { if (part.startsWith("/")) if (!part.toLowerCase().contains("vold")) out.add(part); } } } } return out; } 

MÉTODO 2:

Utilice la biblioteca de soporte v4

 import android.support.v4.content.ContextCompat; 

Simplemente llame al siguiente para obtener una lista de ubicaciones de File de almacenamiento.

  File[] list = ContextCompat.getExternalFilesDirs(myContext, null); 

Sin embargo, las ubicaciones difieren en el uso.

Devuelve rutas absolutas a los directorios específicos de la aplicación en todos los dispositivos de almacenamiento externos donde la aplicación puede colocar los archivos persistentes que posee. Estos archivos son internos a la aplicación y normalmente no son visibles para el usuario como medios.

Los dispositivos de almacenamiento externos que se devuelven aquí se consideran una parte permanente del dispositivo, incluyendo tanto el almacenamiento externo emulado como las ranuras de los medios físicos, como las tarjetas SD en el compartimento de la batería. Las rutas devueltas no incluyen dispositivos transitorios, como unidades flash USB.

Una aplicación puede almacenar datos en cualquiera o todos los dispositivos devueltos. Por ejemplo, una aplicación puede optar por almacenar archivos grandes en el dispositivo con el espacio más disponible

Más información sobre ContextCompat

Son como archivos específicos de la aplicación. Ocultos de otras aplicaciones.

Sólo otra respuesta. Esta respuesta sólo muestra 5.0+ porque creo que la respuesta de Doomknight publicada aquí es la mejor manera de hacer para Android 4.4 y versiones posteriores.

Esto es originalmente publicado aquí ( ¿Hay una manera de obtener el tamaño de la tarjeta SD en Android? ) Por mí para obtener el tamaño de la tarjeta SD externa en Android 5.0+

Para obtener la tarjeta SD externa como un File :

 public File getExternalSdCard() { File externalStorage = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { File storage = new File("/storage"); if(storage.exists()) { File[] files = storage.listFiles(); for (File file : files) { if (file.exists()) { try { if (Environment.isExternalStorageRemovable(file)) { externalStorage = file; break; } } catch (Exception e) { Log.e("TAG", e.toString()); } } } } } else { // do one of many old methods // I believe Doomsknight's method is the best option here } return externalStorage; } 

Nota: Sólo obtengo la "primera" tarjeta sd externa sin embargo, puedes modificarla y devolver ArrayList<File> lugar de File y dejar que el bucle continúe en lugar de llamar break después de que se encuentre el primero.

Con respecto a todas las respuestas agradables, lleno, podría añadir un poco más a esta pregunta para que pueda dar una mayor cobertura para los lectores. En mi respuesta aquí, usaría 2 recursos contable para presentar Almacenamiento externo.

El primer recurso es de Android Programming, The Big Nerd Ranch Guía 2ª edición , capítulo 16, página 294.

El libro describe los métodos básicos y externos de archivos y directorios. Voy a tratar de hacer un resumen de lo que podría ser relevante para su pregunta.

La siguiente parte del libro:

Almacenamiento externo

Su foto necesita más que un lugar en la pantalla. Las imágenes de tamaño completo son demasiado grandes para quedar dentro de una base de datos SQLite, y mucho menos una Intent . Necesitarán un lugar para vivir en el sistema de archivos de su dispositivo. Normalmente, los pondría en su almacenamiento privado. Recuerde que utilizó su almacenamiento privado para guardar su base de datos SQLite. Con métodos como Context.getFileStreamPath(String) y Context.getFilesDir() , puede hacer lo mismo con los archivos regulares, también (que vivirá en una subcarpeta adyacente a la subcarpeta de bases de datos en la que vive la base de datos SQLite)

Métodos básicos de archivos y directorios en Contexto

 | Method | |---------------------------------------------------------------------------------------| |File etFilesDir() | | - Returns a handle to the directory for private application files. | | | |FileInputStream openFileInput(String name) | | - Opens an existing file for input (relative to the files directory). | | | |FileOutputStream openFileOutput(String name, int mode) | | - Opens a file for output, possibly creating it (relative to the files directory). | | | |File getDir(String name, int mode) | | - Gets (and possibly creates) a subdirectory within the files directory. | | | |String[] fileList() | | - Gets a list of file names in the main files directory, such as for use with | | openFileInput(String). | | | |File getCacheDir() | | - Returns a handle to a directory you can use specifically for storing cache files. | | You should take care to keep this directory tidy and use as little space as possible| 

Si está almacenando archivos que sólo necesita su aplicación actual, estos métodos son exactamente lo que necesita.

Por otra parte, si necesitas otra aplicación para escribir en esos archivos, no tienes suerte: mientras hay un indicador Context.MODE_WORLD_READABLE puedes pasar a openFileOutput(String, int) , es obsoleto y no es completamente confiable En sus efectos en dispositivos más nuevos. Si almacena archivos para compartir con otras aplicaciones o para recibir archivos de otras aplicaciones (archivos como imágenes almacenadas), debe guardarlos en el almacenamiento externo.

Hay dos tipos de almacenamiento externo: primario, y todo lo demás. Todos los dispositivos Android tienen al menos una ubicación para almacenamiento externo: la ubicación principal, que se encuentra en la carpeta devuelta por Environment.getExternalStorageDirectory() . Esto puede ser una tarjeta SD, pero hoy en día es más comúnmente integrado en el propio dispositivo. Algunos dispositivos pueden tener almacenamiento externo adicional. Eso caería bajo "todo lo demás".

Contexto proporciona bastantes métodos para obtener en el almacenamiento externo, también. Estos métodos proporcionan maneras fáciles de obtener en su almacenamiento externo primario, y un poco sorta-maneras fáciles de conseguir en todo lo demás. Todos estos métodos almacenan archivos en lugares disponibles públicamente, también, así que ten cuidado con ellos.

Métodos de archivos y directorios externos en contexto

 | Method | | --------------------------------------------------------------------------------------| |File getExternalCacheDir() | | - Returns a handle to a cache folder in primary external storage. Treat it like you do| | getCacheDir(), except a little more carefully. Android is even less likely to clean | | up this folder than the private storage one. | | | |File[] getExternalCacheDirs() | | - Returns cache folders for multiple external storage locations. | | | |File getExternalFilesDir(String) | | - Returns a handle to a folder on primary external storage in which to store regular | | files. If you pass in a type String, you can access a specific subfolder dedicated | | to a particular type of content. Type constants are defined in Environment, where | | they are prefixed with DIRECTORY_. | | For example, pictures go in Environment.DIRECTORY_PICTURES. | | | |File[] getExternalFilesDirs(String) | | - Same as getExternalFilesDir(String), but returns all possible file folders for the | | given type. | | | |File[] getExternalMediaDirs() | | - Returns handles to all the external folders Android makes available for storing | | media – pictures, movies, and music. What makes this different from calling | | getExternalFilesDir(Environment.DIRECTORY_PICTURES) is that the media scanner | | automatically scans this folder. The media scanner makes files available to | | applications that play music, or browse movies and photos, so anything that you | | put in a folder returned by getExternalMediaDirs() will automatically appear in | | those apps. | 

Técnicamente, las carpetas externas proporcionadas anteriormente pueden no estar disponibles, ya que algunos dispositivos utilizan una tarjeta SD extraíble para almacenamiento externo. En la práctica esto raramente es un problema, porque casi todos los dispositivos modernos tienen almacenamiento interno no removible para su almacenamiento "externo". Así que no vale la pena ir a extremos extremos para dar cuenta de ello. Pero recomendamos incluir un código simple para protegerse de la posibilidad, lo que usted hará en un momento.

Permiso de almacenamiento externo

En general, necesita un permiso para escribir o leer desde un almacenamiento externo. Los permisos son valores de cadena bien conocidos que se ponen en el manifiesto mediante la etiqueta <uses-permission> . Le dicen a Android que quiere hacer algo que Android quiere que usted pida permiso.

Aquí, Android espera que usted pida permiso porque quiere imponer alguna responsabilidad. Le dices a Android que necesitas acceder al almacenamiento externo y Android le dirá al usuario que esta es una de las cosas que hace tu aplicación cuando intenta instalarla. De esta forma, nadie se sorprende cuando empiezas a guardar cosas en su tarjeta SD.

En Android 4.4, KitKat, aflojaron esta restricción. Dado que Context.getExternalFilesDir(String) devuelve una carpeta que es específica de su aplicación, tiene sentido que desee poder leer y escribir archivos que viven allí. Así que en Android 4.4 (API 19) y más, no necesita este permiso para esta carpeta. (Pero todavía lo necesita para otros tipos de almacenamiento externo.)

Agregue una línea a su manifiesto que solicite el permiso para leer el almacenamiento externo, pero sólo hasta el listado API 16.5 Solicitar permiso de almacenamiento externo ( AndroidManifest.xml )

 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.bignerdranch.android.criminalintent" > <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="18" /> 

El atributo maxSdkVersion hace que su aplicación sólo solicite este permiso en las versiones de Android que sean anteriores a la API 19, KitKat para Android. Tenga en cuenta que sólo está solicitando leer el almacenamiento externo. También hay un permiso WRITE_EXTERNAL_STORAGE , pero no lo necesita. No escribirá nada en el almacenamiento externo: la aplicación de cámara lo hará por usted

El segundo recurso es este enlace lee todo, pero también puedes ir a la sección Uso de almacenamiento externo .

Referencia:

Más material de lectura:

Descargo de responsabilidad: Esta información fue tomada de Android Programación: The Big Nerd Ranch Guía con el permiso de los autores. Para obtener más información sobre este libro o para comprar una copia, visite bignerdranch.com.

Esta es una forma de crear un nuevo archivo en el almacenamiento externo (SDCard si está presente en el dispositivo o dispositivo de almacenamiento externo si no). Simplemente reemplace "foldername" con el nombre de la carpeta de destino deseada y "filename" con el nombre del archivo que está guardando. Por supuesto, aquí puede ver cómo guardar un archivo genérico, ahora puede buscar cómo guardar imágenes tal vez aquí o lo que sea en un archivo.

 try { File dir = new File(Environment.getExternalStorageDirectory() + "/foldername/"); if (!dir.exists()){ dir.mkdirs(); } File sdCardFile = new File(Environment.getExternalStorageDirectory() + "/foldername/" + fileName ); int num = 1; String fileNameAux = fileName; while (sdCardFile.exists()){ fileNameAux = fileName+"_"+num; sdCardFile = new File(Environment.getExternalStorageDirectory() + "/foldername/" + fileNameAux); num++; } 

Esto también controla que existe el archivo y agrega un número al final del nombre del nuevo archivo para guardarlo.

¡Espero eso ayude!

EDIT: Lo siento, olvidé que tienes que pedir <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> en tu manifiesto (o programatically si prefiere de Marshmallow)

Para versiones debajo de Marshmallow usted puede dar directamente los permisos en el manifiesto.

Sin embargo, para dispositivos con Marshmallow y superiores, debe conceder los permisos en tiempo de ejecución.

Mediante el uso

 Environment.getExternalStorageDirectory(); 

Usted puede tener acceso directo a la tarjeta externa del SD (Montada) Esperanza esto ayuda.

  • Cómo mostrar el indicador de pestaña en la parte superior de las pestañas
  • FileNotFoundException al llamar a webservice
  • Tengo un archivo keystore, ¿cómo puedo proporcionar keyManagers a sslContext en la aplicación de Android?
  • Java vs Objective C en caso de excepción nullpointer
  • Hacer caso de JsonGetter insensible
  • Buenas prácticas: Patrón de diseño para la navegación en pantalla 2D HUD
  • Búsqueda por filtro geográfico con soundcloud api
  • ¿Puedo subir imágenes y texto usando UrlEncodedFormEntity para multipartes?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.