Android obtiene tamaño libre de memoria interna / externa

98

Quiero obtener el tamaño de la memoria libre en el almacenamiento interno / externo de mi dispositivo mediante programación. Estoy usando este código:

StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
long bytesAvailable = (long)stat.getBlockSize() *(long)stat.getBlockCount();
long megAvailable = bytesAvailable / 1048576;
Log.e("","Available MB : "+megAvailable);

File path = Environment.getDataDirectory();
StatFs stat2 = new StatFs(path.getPath());
long blockSize = stat2.getBlockSize();
long availableBlocks = stat2.getAvailableBlocks();
String format =  Formatter.formatFileSize(this, availableBlocks * blockSize);
Log.e("","Format : "+format);

y el resultado que obtengo es:

11-15 10:27:18.844: E/(25822): Available MB : 7572
11-15 10:27:18.844: E/(25822): Format : 869MB

El problema es que quiero obtener la memoria libre de SdCard que es 1,96GBahora mismo. ¿Cómo puedo corregir este código para poder obtener el tamaño libre?

Android-Droid
fuente
A partir del nivel de API 18, cambiaron el nombre del método para terminar con Long. Probablemente necesitaría agregar una verificación del nivel de API antes de esto
Jayshil Dave
Toda la solución Intenté no trabajar con nadie, cuando formateo como almacenamiento interno ... ¿me pueden complacer, cómo lograr esto?
Yogesh Rathi

Respuestas:

182

A continuación se muestra el código para su propósito:

public static boolean externalMemoryAvailable() {
        return android.os.Environment.getExternalStorageState().equals(
                android.os.Environment.MEDIA_MOUNTED);
    }

    public static String getAvailableInternalMemorySize() {
        File path = Environment.getDataDirectory();
        StatFs stat = new StatFs(path.getPath());
        long blockSize = stat.getBlockSizeLong();
        long availableBlocks = stat.getAvailableBlocksLong();
        return formatSize(availableBlocks * blockSize);
    }

    public static String getTotalInternalMemorySize() {
        File path = Environment.getDataDirectory();
        StatFs stat = new StatFs(path.getPath());
        long blockSize = stat.getBlockSizeLong();
        long totalBlocks = stat.getBlockCountLong();
        return formatSize(totalBlocks * blockSize);
    }

    public static String getAvailableExternalMemorySize() {
        if (externalMemoryAvailable()) {
            File path = Environment.getExternalStorageDirectory();
            StatFs stat = new StatFs(path.getPath());
            long blockSize = stat.getBlockSizeLong();
            long availableBlocks = stat.getAvailableBlocksLong();
            return formatSize(availableBlocks * blockSize);
        } else {
            return ERROR;
        }
    }

    public static String getTotalExternalMemorySize() {
        if (externalMemoryAvailable()) {
            File path = Environment.getExternalStorageDirectory();
            StatFs stat = new StatFs(path.getPath());
            long blockSize = stat.getBlockSizeLong();
            long totalBlocks = stat.getBlockCountLong();
            return formatSize(totalBlocks * blockSize);
        } else {
            return ERROR;
        }
    }

    public static String formatSize(long size) {
        String suffix = null;

        if (size >= 1024) {
            suffix = "KB";
            size /= 1024;
            if (size >= 1024) {
                suffix = "MB";
                size /= 1024;
            }
        }

        StringBuilder resultBuffer = new StringBuilder(Long.toString(size));

        int commaOffset = resultBuffer.length() - 3;
        while (commaOffset > 0) {
            resultBuffer.insert(commaOffset, ',');
            commaOffset -= 3;
        }

        if (suffix != null) resultBuffer.append(suffix);
        return resultBuffer.toString();
    }

Obtener tamaño de RAM

ActivityManager actManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
MemoryInfo memInfo = new ActivityManager.MemoryInfo();
actManager.getMemoryInfo(memInfo);
long totalMemory = memInfo.totalMem;
Dinesh Prajapati
fuente
2
getBlockSize()y getBlockCountestán en desuso.
Nima G
2
@DineshPrajapati Gracias por la respuesta, tengo una consulta, si uso Environment.getRootDirectory () en lugar de Environment.getDataDirectory para calcular el almacenamiento interno, obtengo algo de salida ... esto se refiere a la memoria interna otra memoria ...
AK Joshi
3
@DineshPrajapati .. Probado en MOTO G2 Obteniendo datos incorrectos para almacenamiento externo
AK Joshi
1
Use Long al final para niveles de API más nuevos (> 18)
Gun2sh
1
Muchas gracias por compartir conocimientos
Kishan Soni
40

Esta es la forma en que lo hice:

StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
long bytesAvailable;
if (android.os.Build.VERSION.SDK_INT >= 
    android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
    bytesAvailable = stat.getBlockSizeLong() * stat.getAvailableBlocksLong();
}
else {
    bytesAvailable = (long)stat.getBlockSize() * (long)stat.getAvailableBlocks();
}
long megAvailable = bytesAvailable / (1024 * 1024);
Log.e("","Available MB : "+megAvailable);
Android-Droid
fuente
2
pero esto es depravado :(
abbasalim
@ ArMo372, ¿Ustedes encontraron el código de reemplazo para esto?
SimpleCoder
3
Simplemente reemplace getBlockSizey getAvailableBlockscon getBlockSizeLongy getAvailableBlocksLong.
smg
1
esto no está obteniendo el espacio disponible adecuado. Esto está obteniendo 1141 en lugar de 1678 @smg
1
La solución no funciona cuando formateo como almacenamiento interno ... ¿me pueden complacer, cómo lograr esto?
Yogesh Rathi
27

Desde API 9 puedes hacer:

long freeBytesInternal = new File(ctx.getFilesDir().getAbsoluteFile().toString()).getFreeSpace();
long freeBytesExternal = new File(getExternalFilesDir(null).toString()).getFreeSpace();
Tzoiker
fuente
2
File.getUsableSpace () probablemente sea mejor porque probablemente no se esté ejecutando como root.
Mark
Los File.getUsableSpace()ve como un método más fácil de usar en lugar de utilizar StatFs. ¿Por qué debería usar StatFs@MarkCarter?
StuStirling
1
@ DiscoS2 Usaría StatFs si su minSdkVersion es menor que 9.
Mark
1
¿Cómo supervisaría también los cambios de almacenamiento?
desarrollador de Android
24

Para obtener todas las carpetas de almacenamiento disponibles (incluidas las tarjetas SD), primero obtenga los archivos de almacenamiento:

File internalStorageFile=getFilesDir();
File[] externalStorageFiles=ContextCompat.getExternalFilesDirs(this,null);

Entonces puede obtener el tamaño disponible de cada uno de ellos.

Hay 3 formas de hacerlo:

API 8 y siguientes:

StatFs stat=new StatFs(file.getPath());
long availableSizeInBytes=stat.getBlockSize()*stat.getAvailableBlocks();

API 9 y superior:

long availableSizeInBytes=file.getFreeSpace();

API 18 y superior (no es necesaria si la anterior está bien):

long availableSizeInBytes=new StatFs(file.getPath()).getAvailableBytes(); 

Para obtener una cadena con formato agradable de lo que tiene ahora, puede usar:

String formattedResult=android.text.format.Formatter.formatShortFileSize(this,availableSizeInBytes);

o puede usar esto en caso de que desee ver el número de bytes exacto, pero muy bien:

NumberFormat.getInstance().format(availableSizeInBytes);

Tenga en cuenta que creo que el almacenamiento interno podría ser el mismo que el primer almacenamiento externo, ya que el primero es el emulado.


EDITAR: Usando StorageVolume en Android Q y superior, creo que es posible obtener el espacio libre de cada uno, usando algo como:

    val storageManager = getSystemService(Context.STORAGE_SERVICE) as StorageManager
    val storageVolumes = storageManager.storageVolumes
    AsyncTask.execute {
        for (storageVolume in storageVolumes) {
            val uuid: UUID = storageVolume.uuid?.let { UUID.fromString(it) } ?: StorageManager.UUID_DEFAULT
            val allocatableBytes = storageManager.getAllocatableBytes(uuid)
            Log.d("AppLog", "allocatableBytes:${android.text.format.Formatter.formatShortFileSize(this,allocatableBytes)}")
        }
    }

No estoy seguro de si esto es correcto, y no puedo encontrar una manera de obtener el tamaño total de cada uno, así que escribí sobre esto aquí y pregunté al respecto aquí .

desarrollador de Android
fuente
1
¿Cómo obtener espacio libre en una tarjeta SD extraíble (o unidad flash USB OTG) en dispositivos con API 23? new StatFs (file.getPath ()). getAvailableBytes () o file.getUsableSpace () da 972546048 bytes independientemente del tamaño de almacenamiento real en Nexus 5 (Marshmallow 6.0.1).
ausente
@isabsent Nexus 5 no tiene ranura para tarjetas SD. ¿Cómo lo comprobaste?
desarrollador de Android
Lo he comprobado con una unidad flash USB OTG.
ausente
@isabsent Nunca lo usé. Lo siento. ¿Funciona bien en API 22 e inferior?
desarrollador de Android
1
@Smeet ¿Es posible que lo pruebes en Android 6 o superior? Si es así, tal vez sea un problema como este: code.google.com/p/android/issues/detail?id=200326
desarrollador de Android
9

@ Android-Droid: está equivocado respecto Environment.getExternalStorageDirectory()al almacenamiento externo que no tiene que ser una tarjeta SD, también se puede montar en la memoria interna. Ver:

Encuentra una ubicación de tarjeta SD externa

Sharp80
fuente
7

Prueba este sencillo fragmento

    public static String readableFileSize() {
    long availableSpace = -1L;
    StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
        availableSpace = (long) stat.getBlockSizeLong() * (long) stat.getAvailableBlocksLong();
    else
        availableSpace = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();

    if(availableSpace <= 0) return "0";
    final String[] units = new String[] { "B", "kB", "MB", "GB", "TB" };
    int digitGroups = (int) (Math.log10(availableSpace)/Math.log10(1024));
    return new DecimalFormat("#,##0.#").format(availableSpace/Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}
Ness Tyagi
fuente
Gracias, pero tengo el java.lang.ArrayIndexOutOfBoundsException: length=5; index=-2147483648error, parece que el digitGroupsresultado es -2147483648.
Acuña
La solución no funciona cuando formateo como almacenamiento interno ... ¿me pueden complacer, cómo lograr esto?
Yogesh Rathi
6

Es muy fácil averiguar el almacenamiento disponible si obtiene una ruta de almacenamiento interna y externa. También la ruta de almacenamiento externo del teléfono es realmente muy fácil de averiguar usando

Environment.getExternalStorageDirectory (). GetPath ();

Así que solo me estoy concentrando en cómo encontrar las rutas de almacenamiento externo extraíble como tarjeta SD extraíble, USB OTG (no probado USB OTG ya que no tengo USB OTG).

El método siguiente le dará una lista de todas las posibles rutas de almacenamiento extraíbles externas.

 /**
     * This method returns the list of removable storage and sdcard paths.
     * I have no USB OTG so can not test it. Is anybody can test it, please let me know
     * if working or not. Assume 0th index will be removable sdcard path if size is
     * greater than 0.
     * @return the list of removable storage paths.
     */
    public static HashSet<String> getExternalPaths()
    {
    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.replace("/media_rw","").replace("mnt", "storage"));
                        }
                    }
                }
            }
        }
    }
    //Phone's external storage path (Not removal SDCard path)
    String phoneExternalPath = Environment.getExternalStorageDirectory().getPath();

    //Remove it if already exist to filter all the paths of external removable storage devices
    //like removable sdcard, USB OTG etc..
    //When I tested it in ICE Tab(4.4.2), Swipe Tab(4.0.1) with removable sdcard, this method includes
    //phone's external storage path, but when i test it in Moto X Play (6.0) with removable sdcard,
    //this method does not include phone's external storage path. So I am going to remvoe the phone's
    //external storage path to make behavior consistent in all the phone. Ans we already know and it easy
    // to find out the phone's external storage path.
    out.remove(phoneExternalPath);

    return out;
}
Smeet
fuente
Según recuerdo, es posible que el uso de nombres constantes para el manejo de rutas no funcione en algunos dispositivos, ya que algunos pueden tener sus propias rutas. Espero que este no sea el caso. +1 por el esfuerzo.
desarrollador de Android
1
@androiddeveloper Gracias cariño por votar. Necesito el apoyo de todos para probar este código en su dispositivo porque no tengo todos los dispositivos, pero los probé en 4 dispositivos diferentes y funcionan bien. Comente aquí que no funciona en el móvil de nadie.
Smeet
La solución no funciona cuando formateo como almacenamiento interno ... ¿me pueden complacer, cómo lograr esto?
Yogesh Rathi
4

Adición rápida al tema de la memoria externa

No se confunda con el nombre del método externalMemoryAvailable()en la respuesta de Dinesh Prajapati.

Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())le proporciona el estado actual de la memoria, si el medio está presente y montado en su punto de montaje con acceso de lectura / escritura. Conseguirástrue incluso en dispositivos sin tarjetas SD, como Nexus 5. Pero aún así es un método 'imprescindible' antes de cualquier operación con el almacenamiento.

Para verificar si hay una tarjeta SD en su dispositivo, puede usar el método ContextCompat.getExternalFilesDirs()

No muestra dispositivos transitorios, como unidades flash USB.

También tenga en cuenta que ContextCompat.getExternalFilesDirs()en Android 4.3 y versiones inferiores siempre se devolverá solo 1 entrada (tarjeta SD si está disponible, de lo contrario, interna). Puedes leer más sobre esto aquí .

  public static boolean isSdCardOnDevice(Context context) {
    File[] storages = ContextCompat.getExternalFilesDirs(context, null);
    if (storages.length > 1 && storages[0] != null && storages[1] != null)
        return true;
    else
        return false;
}

en mi caso fue suficiente, pero no olvides que algunos de los dispositivos Android pueden tener 2 tarjetas SD, así que si las necesitas todas, ajusta el código anterior.

Kirill Karmazin
fuente
2
@RequiresApi(api = Build.VERSION_CODES.O)
private void showStorageVolumes() {
    StorageStatsManager storageStatsManager = (StorageStatsManager) getSystemService(Context.STORAGE_STATS_SERVICE);
    StorageManager storageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
    if (storageManager == null || storageStatsManager == null) {
        return;
    }
    List<StorageVolume> storageVolumes = storageManager.getStorageVolumes();
    for (StorageVolume storageVolume : storageVolumes) {
        final String uuidStr = storageVolume.getUuid();
        final UUID uuid = uuidStr == null ? StorageManager.UUID_DEFAULT : UUID.fromString(uuidStr);
        try {
            Log.d("AppLog", "storage:" + uuid + " : " + storageVolume.getDescription(this) + " : " + storageVolume.getState());
            Log.d("AppLog", "getFreeBytes:" + Formatter.formatShortFileSize(this, storageStatsManager.getFreeBytes(uuid)));
            Log.d("AppLog", "getTotalBytes:" + Formatter.formatShortFileSize(this, storageStatsManager.getTotalBytes(uuid)));
        } catch (Exception e) {
            // IGNORED
        }
    }
}

La clase StorageStatsManager introdujo Android O y superior, que puede brindarle bytes libres y totales en almacenamiento externo / interno. Para obtener información detallada con el código fuente, puede leer mi siguiente artículo. puedes usar la reflexión para menos que Android O

https://medium.com/cashify-engineering/how-to-get-storage-stats-in-android-o-api-26-4b92eca6805b

Brijesh Gupta
fuente
2

Esta es la forma en que lo hice ...

memoria total interna

double totalSize = new File(getApplicationContext().getFilesDir().getAbsoluteFile().toString()).getTotalSpace();
double totMb = totalSize / (1024 * 1024);

Tamaño libre interno

 double availableSize = new File(getApplicationContext().getFilesDir().getAbsoluteFile().toString()).getFreeSpace();
    double freeMb = availableSize/ (1024 * 1024);

Memoria externa libre y total

 long freeBytesExternal =  new File(getExternalFilesDir(null).toString()).getFreeSpace();
       int free = (int) (freeBytesExternal/ (1024 * 1024));
        long totalSize =  new File(getExternalFilesDir(null).toString()).getTotalSpace();
        int total= (int) (totalSize/ (1024 * 1024));
       String availableMb = free+"Mb out of "+total+"MB";
makvine
fuente
0

Acerca de la menory externa, hay otra forma:
File external = Environment.getExternalStorageDirectory(); free:external.getFreeSpace(); total:external.getTotalSpace();

Edward Anderson
fuente
0

Después de verificar el código de escritura de una solución diferente, este es un código completo para encontrar

  • Memoria externa total
  • Memoria externa libre
  • Memoria externa usada
  • Memoria interna total
  • Memoria interna usada
  • Memoria interna libre

'' ''

object DeviceMemoryUtil {
private const val error: String = "Something went wrog"
private const val noExternalMemoryDetected = "No external Storage detected"
private var totalExternalMemory: Long = 0
private var freeExternalMemory: Long = 0
private var totalInternalStorage: Long = 0
private var freeInternalStorage: Long = 0

/**
 * Checks weather external memory is available or not
 */
private fun externalMemoryAvailable(): Boolean {
    return Environment.getExternalStorageState() ==
            Environment.MEDIA_MOUNTED
}

/**
 *Gives total external memory
 * @return String Size of external memory
 * @return Boolean True if memory size is returned
 */
fun getTotalExternalMemorySize(): Pair<String?, Boolean> {
    val dirs: Array<File> = ContextCompat.getExternalFilesDirs(CanonApplication.getCanonAppInstance(), null)
    return if (externalMemoryAvailable()) {
        if (dirs.size > 1) {
            val stat = StatFs(dirs[1].path)
            val blockSize = stat.blockSizeLong
            val totalBlocks = stat.blockCountLong
            var totalExternalSize = totalBlocks * blockSize
            totalExternalMemory = totalExternalSize
            Pair(formatSize(totalExternalSize), true)
        } else {
            Pair(error, false)
        }
    } else {
        Pair(noExternalMemoryDetected, false)
    }
}

/**
 * Gives free external memory size
 * @return String Size of free external memory
 * @return Boolean True if memory size is returned
 */
fun getAvailableExternalMemorySize(): Pair<String?, Boolean> {
    val dirs: Array<File> = ContextCompat.getExternalFilesDirs(CanonApplication.getCanonAppInstance(), null)
    if (externalMemoryAvailable()) {
        return if (dirs.size > 1) {
            val stat = StatFs(dirs[1].path)
            val blockSize = stat.blockSizeLong
            val availableBlocks = stat.availableBlocksLong
            var freeExternalSize = blockSize * availableBlocks
            freeExternalMemory = freeExternalSize
            Pair(formatSize(freeExternalSize), true)
        } else {
            Pair(error, false)
        }
    } else {
        return Pair(noExternalMemoryDetected, false)
    }
}

/**
 * Gives used external memory size
 *  @return String Size of used external memory
 * @return Boolean True if memory size is returned
 */
fun getUsedExternalMemorySize(): Pair<String?, Boolean> {
    return if (externalMemoryAvailable()) {
        val totalExternalSize = getTotalExternalMemorySize()
        val freeExternalSize = getAvailableExternalMemorySize()
        if (totalExternalSize.second && freeExternalSize.second) {
            var usedExternalVolume = totalExternalMemory - freeExternalMemory
            Pair(formatSize(usedExternalVolume), true)
        } else {
            Pair(error, false)
        }
    } else {
        Pair(noExternalMemoryDetected, false)
    }
}

/**
 *Formats the long to size of memory in gb,mb etc.
 * @param size Size of memory
 */
fun formatSize(size: Long): String? {
    return android.text.format.Formatter.formatFileSize(CanonApplication.getCanonAppInstance(), size)
}

/**
 * Gives total internal memory size
 *  @return String Size of total internal memory
 * @return Boolean True if memory size is returned
 */
fun getTotalInternalStorage(): Pair<String?, Boolean> {
    if (showStorageVolumes()) {
        return Pair(formatSize(totalInternalStorage), true)
    } else {
        return Pair(error, false)
    }

}

/**
 * Gives free or available internal memory size
 *  @return String Size of free internal memory
 * @return Boolean True if memory size is returned
 */
fun getFreeInternalStorageVolume(): Pair<String?, Boolean> {
    return if (showStorageVolumes()) {
        Pair(formatSize(freeInternalStorage), true)
    } else {
        Pair(error, false)
    }
}

/**
 *For calculation of internal storage
 */
private fun showStorageVolumes(): Boolean {
    val storageManager = CanonApplication.canonApplicationInstance.applicationContext.getSystemService(Context.STORAGE_SERVICE) as StorageManager
    val storageStatsManager = CanonApplication.canonApplicationInstance.applicationContext.getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager
    if (storageManager == null || storageStatsManager == null) {
        return false
    }
    val storageVolumes: List<StorageVolume> = storageManager.storageVolumes
    for (storageVolume in storageVolumes) {
        var uuidStr: String? = null
        storageVolume.uuid?.let {
            uuidStr = it
        }
        val uuid: UUID = if (uuidStr == null) StorageManager.UUID_DEFAULT else UUID.fromString(uuidStr)
        return try {
            freeInternalStorage = storageStatsManager.getFreeBytes(uuid)
            totalInternalStorage = storageStatsManager.getTotalBytes(uuid)
            true
        } catch (e: Exception) {
            // IGNORED
            false
        }
    }
    return false
}

fun getTotalInternalExternalMemory(): Pair<Long?, Boolean> {
    if (externalMemoryAvailable()) {
        if (getTotalExternalMemorySize().second) {
            if (getTotalInternalStorage().second) {
                return Pair(totalExternalMemory + totalInternalStorage, true)
            } else {
                return Pair(0, false)
            }
        }
        return Pair(0, false)
    } else {
        if (getTotalInternalStorage().second) {
            return Pair(totalInternalStorage, true)
        } else {
            return Pair(0, false)
        }
    }

}

fun getTotalFreeStorage(): Pair<Long,Boolean> {
    if (externalMemoryAvailable()){
        if(getFreeInternalStorageVolume().second){
            getFreeInternalStorageVolume()
            getAvailableExternalMemorySize()
                return Pair(freeExternalMemory + freeInternalStorage,true)
        }
        else{
            return Pair(0,false)
        }
    }
    else {
        if (getFreeInternalStorageVolume().second){
            getFreeInternalStorageVolume()
            return Pair(freeInternalStorage,true)
        }
      else{
            return Pair(0,false)
        }
    }

}}
Sahil Bansal
fuente