android - pasar - cómo cambiar de almacenamiento interno a tarjeta sd samsung
Directorio de almacenamiento externo abierto de Android(sdcard) para almacenar archivos (7)
Quiero abrir la ruta del directorio de almacenamiento externo para guardar el archivo de forma programática. Lo intenté pero no recibí la ruta de la tarjeta SD. ¿Cómo puedo hacer esto? ¿Hay alguna solución para esto?
private File path = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "");
o
private File path = new File(Environment.getExternalStorageDirectory() + "");
Intenté obtener la ruta desde arriba de ambos métodos, pero ambos apuntan a la memoria interna.
Cuando abrimos la memoria de almacenamiento si sdcard está presente, se mostrará como debajo-
dispositivo de almacenamiento y tarjeta de memoria SD.
Quiero obtener una ruta de memoria SD a través de la codificación. He dado permisos en manifiesto
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Quiero abrir la ruta del directorio de almacenamiento externo para guardar el archivo de forma programática. Lo intenté pero no recibí la ruta de la tarjeta SD. ¿Cómo puedo hacer esto? ¿Hay alguna solución para esto?
Para almacenar los archivos de su aplicación en la tarjeta SD, debe usar el método File[] getExternalFilesDirs (String type)
en la clase Context
. Generalmente, la segunda ruta devuelta sería la ruta de almacenamiento para la tarjeta microSD (si corresponde).
En mi teléfono, la segunda ruta devuelta era /storage/sdcard1/Android/data/your.application.package.appname/files
después de pasar null
como argumento a getExternalFilesDirs (String type)
. Pero la ruta puede variar en diferentes teléfonos, diferentes versiones de Android.
Tanto File getExternalStorageDirectory ()
como File getExternalStoragePublicDirectory (String type)
en Environment
clase Environment
pueden devolver el directorio de la tarjeta SD o el directorio de la memoria interna según el modelo de su teléfono y la versión del sistema operativo Android.
Porque según la guía oficial de Android, el almacenamiento externo puede ser
medios de almacenamiento extraíbles (como una tarjeta SD) o un almacenamiento interno (no extraíble).
La terminología de almacenamiento interno y externo según Google / documentos oficiales de Android es bastante diferente de lo que pensamos.
¡He estado teniendo exactamente el mismo problema!
Para obtener la tarjeta SD interna, puede usar
String extStore = System.getenv("EXTERNAL_STORAGE");
File f_exts = new File(extStore);
Para obtener la tarjeta SD externa, puede usar
String secStore = System.getenv("SECONDARY_STORAGE");
File f_secs = new File(secStore);
En ejecutar el código
extStore = "/storage/emulated/legacy"
secStore = "/storage/extSdCarcd"
¡funciona perfectamente!
Complementando la respuesta rijul gupta :
String strSDCardPath = System.getenv("SECONDARY_STORAGE");
if ((strSDCardPath == null) || (strSDCardPath.length() == 0)) {
strSDCardPath = System.getenv("EXTERNAL_SDCARD_STORAGE");
}
//If may get a full path that is not the right one, even if we don''t have the SD Card there.
//We just need the "/mnt/extSdCard/" i.e and check if it''s writable
if(strSDCardPath != null) {
if (strSDCardPath.contains(":")) {
strSDCardPath = strSDCardPath.substring(0, strSDCardPath.indexOf(":"));
}
File externalFilePath = new File(strSDCardPath);
if (externalFilePath.exists() && externalFilePath.canWrite()){
//do what you need here
}
}
El almacenamiento interno se conoce como "almacenamiento externo" en la API.
Como se menciona en la documentación del Environment
Nota: no se confunda con la palabra "externo" aquí. Este directorio se puede considerar mejor como almacenamiento multimedia / compartido. Es un sistema de archivos que puede contener una cantidad relativamente grande de datos y que se comparte en todas las aplicaciones (no impone permisos). Tradicionalmente, esta es una tarjeta SD, pero también se puede implementar como almacenamiento integrado en un dispositivo que es distinto del almacenamiento interno protegido y se puede montar como un sistema de archivos en una computadora.
Para distinguir si "Environment.getExternalStorageDirectory ()" realmente devolvió físicamente el almacenamiento interno o externo, llame a Environment.isExternalStorageEmulated (). Si es emulado, entonces es interno. En dispositivos más nuevos que tienen almacenamiento interno y ranura para tarjeta SD, Environment.getExternalStorageDirectory () siempre devolverá el almacenamiento interno. Mientras que en dispositivos más antiguos que solo tienen sdcard como una opción de almacenamiento de medios, siempre devolverá la tarjeta sd.
No hay forma de recuperar todos los almacenamientos utilizando la API actual de Android.
He creado un ayudante basado en el método de Vitaliy Polchuk en la respuesta a continuación
¿Cómo puedo obtener la lista de almacenamiento externo montado de un dispositivo Android?
NOTA: al iniciar el almacenamiento secundario de KitKat solo se puede acceder LECTURA , es posible que desee comprobar la capacidad de escritura mediante el siguiente método
/**
* Checks whether the StorageVolume is read-only
*
* @param volume
* StorageVolume to check
* @return true, if volume is mounted read-only
*/
public static boolean isReadOnly(@NonNull final StorageVolume volume) {
if (volume.mFile.equals(Environment.getExternalStorageDirectory())) {
// is a primary storage, check mounted state by Environment
return android.os.Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED_READ_ONLY);
} else {
if (volume.getType() == Type.USB) {
return volume.isReadOnly();
}
//is not a USB storagem so it''s read-only if it''s mounted read-only or if it''s a KitKat device
return volume.isReadOnly() || Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
}
}
Clase StorageHelper
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;
import android.os.Environment;
public final class StorageHelper {
//private static final String TAG = "StorageHelper";
private StorageHelper() {
}
private static final String STORAGES_ROOT;
static {
final String primaryStoragePath = Environment.getExternalStorageDirectory()
.getAbsolutePath();
final int index = primaryStoragePath.indexOf(File.separatorChar, 1);
if (index != -1) {
STORAGES_ROOT = primaryStoragePath.substring(0, index + 1);
} else {
STORAGES_ROOT = File.separator;
}
}
private static final String[] AVOIDED_DEVICES = new String[] {
"rootfs", "tmpfs", "dvpts", "proc", "sysfs", "none"
};
private static final String[] AVOIDED_DIRECTORIES = new String[] {
"obb", "asec"
};
private static final String[] DISALLOWED_FILESYSTEMS = new String[] {
"tmpfs", "rootfs", "romfs", "devpts", "sysfs", "proc", "cgroup", "debugfs"
};
/**
* Returns a list of mounted {@link StorageVolume}s Returned list always
* includes a {@link StorageVolume} for
* {@link Environment#getExternalStorageDirectory()}
*
* @param includeUsb
* if true, will include USB storages
* @return list of mounted {@link StorageVolume}s
*/
public static List<StorageVolume> getStorages(final boolean includeUsb) {
final Map<String, List<StorageVolume>> deviceVolumeMap = new HashMap<String, List<StorageVolume>>();
// this approach considers that all storages are mounted in the same non-root directory
if (!STORAGES_ROOT.equals(File.separator)) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("/proc/mounts"));
String line;
while ((line = reader.readLine()) != null) {
// Log.d(TAG, line);
final StringTokenizer tokens = new StringTokenizer(line, " ");
final String device = tokens.nextToken();
// skipped devices that are not sdcard for sure
if (arrayContains(AVOIDED_DEVICES, device)) {
continue;
}
// should be mounted in the same directory to which
// the primary external storage was mounted
final String path = tokens.nextToken();
if (!path.startsWith(STORAGES_ROOT)) {
continue;
}
// skip directories that indicate tha volume is not a storage volume
if (pathContainsDir(path, AVOIDED_DIRECTORIES)) {
continue;
}
final String fileSystem = tokens.nextToken();
// don''t add ones with non-supported filesystems
if (arrayContains(DISALLOWED_FILESYSTEMS, fileSystem)) {
continue;
}
final File file = new File(path);
// skip volumes that are not accessible
if (!file.canRead() || !file.canExecute()) {
continue;
}
List<StorageVolume> volumes = deviceVolumeMap.get(device);
if (volumes == null) {
volumes = new ArrayList<StorageVolume>(3);
deviceVolumeMap.put(device, volumes);
}
final StorageVolume volume = new StorageVolume(device, file, fileSystem);
final StringTokenizer flags = new StringTokenizer(tokens.nextToken(), ",");
while (flags.hasMoreTokens()) {
final String token = flags.nextToken();
if (token.equals("rw")) {
volume.mReadOnly = false;
break;
} else if (token.equals("ro")) {
volume.mReadOnly = true;
break;
}
}
volumes.add(volume);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
// ignored
}
}
}
}
// remove volumes that are the same devices
boolean primaryStorageIncluded = false;
final File externalStorage = Environment.getExternalStorageDirectory();
final List<StorageVolume> volumeList = new ArrayList<StorageVolume>();
for (final Entry<String, List<StorageVolume>> entry : deviceVolumeMap.entrySet()) {
final List<StorageVolume> volumes = entry.getValue();
if (volumes.size() == 1) {
// go ahead and add
final StorageVolume v = volumes.get(0);
final boolean isPrimaryStorage = v.file.equals(externalStorage);
primaryStorageIncluded |= isPrimaryStorage;
setTypeAndAdd(volumeList, v, includeUsb, isPrimaryStorage);
continue;
}
final int volumesLength = volumes.size();
for (int i = 0; i < volumesLength; i++) {
final StorageVolume v = volumes.get(i);
if (v.file.equals(externalStorage)) {
primaryStorageIncluded = true;
// add as external storage and continue
setTypeAndAdd(volumeList, v, includeUsb, true);
break;
}
// if that was the last one and it''s not the default external
// storage then add it as is
if (i == volumesLength - 1) {
setTypeAndAdd(volumeList, v, includeUsb, false);
}
}
}
// add primary storage if it was not found
if (!primaryStorageIncluded) {
final StorageVolume defaultExternalStorage = new StorageVolume("", externalStorage, "UNKNOWN");
defaultExternalStorage.mEmulated = Environment.isExternalStorageEmulated();
defaultExternalStorage.mType =
defaultExternalStorage.mEmulated ? StorageVolume.Type.INTERNAL
: StorageVolume.Type.EXTERNAL;
defaultExternalStorage.mRemovable = Environment.isExternalStorageRemovable();
defaultExternalStorage.mReadOnly =
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY);
volumeList.add(0, defaultExternalStorage);
}
return volumeList;
}
/**
* Sets {@link StorageVolume.Type}, removable and emulated flags and adds to
* volumeList
*
* @param volumeList
* List to add volume to
* @param v
* volume to add to list
* @param includeUsb
* if false, volume with type {@link StorageVolume.Type#USB} will
* not be added
* @param asFirstItem
* if true, adds the volume at the beginning of the volumeList
*/
private static void setTypeAndAdd(final List<StorageVolume> volumeList,
final StorageVolume v,
final boolean includeUsb,
final boolean asFirstItem) {
final StorageVolume.Type type = resolveType(v);
if (includeUsb || type != StorageVolume.Type.USB) {
v.mType = type;
if (v.file.equals(Environment.getExternalStorageDirectory())) {
v.mRemovable = Environment.isExternalStorageRemovable();
} else {
v.mRemovable = type != StorageVolume.Type.INTERNAL;
}
v.mEmulated = type == StorageVolume.Type.INTERNAL;
if (asFirstItem) {
volumeList.add(0, v);
} else {
volumeList.add(v);
}
}
}
/**
* Resolved {@link StorageVolume} type
*
* @param v
* {@link StorageVolume} to resolve type for
* @return {@link StorageVolume} type
*/
private static StorageVolume.Type resolveType(final StorageVolume v) {
if (v.file.equals(Environment.getExternalStorageDirectory())
&& Environment.isExternalStorageEmulated()) {
return StorageVolume.Type.INTERNAL;
} else if (containsIgnoreCase(v.file.getAbsolutePath(), "usb")) {
return StorageVolume.Type.USB;
} else {
return StorageVolume.Type.EXTERNAL;
}
}
/**
* Checks whether the array contains object
*
* @param array
* Array to check
* @param object
* Object to find
* @return true, if the given array contains the object
*/
private static <T> boolean arrayContains(T[] array, T object) {
for (final T item : array) {
if (item.equals(object)) {
return true;
}
}
return false;
}
/**
* Checks whether the path contains one of the directories
*
* For example, if path is /one/two, it returns true input is "one" or
* "two". Will return false if the input is one of "one/two", "/one" or
* "/two"
*
* @param path
* path to check for a directory
* @param dirs
* directories to find
* @return true, if the path contains one of the directories
*/
private static boolean pathContainsDir(final String path, final String[] dirs) {
final StringTokenizer tokens = new StringTokenizer(path, File.separator);
while (tokens.hasMoreElements()) {
final String next = tokens.nextToken();
for (final String dir : dirs) {
if (next.equals(dir)) {
return true;
}
}
}
return false;
}
/**
* Checks ifString contains a search String irrespective of case, handling.
* Case-insensitivity is defined as by
* {@link String#equalsIgnoreCase(String)}.
*
* @param str
* the String to check, may be null
* @param searchStr
* the String to find, may be null
* @return true if the String contains the search String irrespective of
* case or false if not or {@code null} string input
*/
public static boolean containsIgnoreCase(final String str, final String searchStr) {
if (str == null || searchStr == null) {
return false;
}
final int len = searchStr.length();
final int max = str.length() - len;
for (int i = 0; i <= max; i++) {
if (str.regionMatches(true, i, searchStr, 0, len)) {
return true;
}
}
return false;
}
/**
* Represents storage volume information
*/
public static final class StorageVolume {
/**
* Represents {@link StorageVolume} type
*/
public enum Type {
/**
* Device built-in internal storage. Probably points to
* {@link Environment#getExternalStorageDirectory()}
*/
INTERNAL,
/**
* External storage. Probably removable, if no other
* {@link StorageVolume} of type {@link #INTERNAL} is returned by
* {@link StorageHelper#getStorages(boolean)}, this might be
* pointing to {@link Environment#getExternalStorageDirectory()}
*/
EXTERNAL,
/**
* Removable usb storage
*/
USB
}
/**
* Device name
*/
public final String device;
/**
* Points to mount point of this device
*/
public final File file;
/**
* File system of this device
*/
public final String fileSystem;
/**
* if true, the storage is mounted as read-only
*/
private boolean mReadOnly;
/**
* If true, the storage is removable
*/
private boolean mRemovable;
/**
* If true, the storage is emulated
*/
private boolean mEmulated;
/**
* Type of this storage
*/
private Type mType;
StorageVolume(String device, File file, String fileSystem) {
this.device = device;
this.file = file;
this.fileSystem = fileSystem;
}
/**
* Returns type of this storage
*
* @return Type of this storage
*/
public Type getType() {
return mType;
}
/**
* Returns true if this storage is removable
*
* @return true if this storage is removable
*/
public boolean isRemovable() {
return mRemovable;
}
/**
* Returns true if this storage is emulated
*
* @return true if this storage is emulated
*/
public boolean isEmulated() {
return mEmulated;
}
/**
* Returns true if this storage is mounted as read-only
*
* @return true if this storage is mounted as read-only
*/
public boolean isReadOnly() {
return mReadOnly;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((file == null) ? 0 : file.hashCode());
return result;
}
/**
* Returns true if the other object is StorageHelper and it''s
* {@link #file} matches this one''s
*
* @see Object#equals(Object)
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final StorageVolume other = (StorageVolume) obj;
if (file == null) {
return other.file == null;
}
return file.equals(other.file);
}
@Override
public String toString() {
return file.getAbsolutePath() + (mReadOnly ? " ro " : " rw ") + mType + (mRemovable ? " R " : "")
+ (mEmulated ? " E " : "") + fileSystem;
}
}
}
Espero que haya funcionado para ti:
File yourFile = new File(Environment.getExternalStorageDirectory(), "textarabics.txt");
Esto le dará una ruta de tarjeta SD:
File path = Environment.getExternalStorageDirectory();
Prueba esto:
String pathName = "/mnt/";
o prueba esto:
String pathName = "/storage/";
Intenta usar
new File(Environment.getExternalStorageDirectory(),"somefilename");
Y no te olvides de agregar permisos WRITE_EXTERNAL STORAGE y READ_EXTERNAL STORAGE
tomando la respuesta de @ rijul adelante, no funciona en malvavisco y versiones anteriores:
//for pre-marshmallow versions
String path = System.getenv("SECONDARY_STORAGE");
// For Marshmallow, use getExternalCacheDirs() instead of System.getenv("SECONDARY_STORAGE")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
File[] externalCacheDirs = mContext.getExternalCacheDirs();
for (File file : externalCacheDirs) {
if (Environment.isExternalStorageRemovable(file)) {
// Path is in format /storage.../Android....
// Get everything before /Android
path = file.getPath().split("/Android")[0];
break;
}
}
}
// Android avd emulator doesn''t support this variable name so using other one
if ((null == path) || (path.length() == 0))
path = Environment.getExternalStorageDirectory().getAbsolutePath();