116

I want to get the size of free memory on internal/external storage of my device programmatically. I'm using this piece of code :

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);

and the result which I'm getting is :

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

The problem is that I want to get the free memory of SdCard which is 1,96GB right now. How can I fix this code so I can get the free size ?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Android-Droid
  • 14,365
  • 41
  • 114
  • 185
  • 1
    As of API level 18 they have renamed the method to end with Long. Probably you would need to add a check of API level prior to it – Jayshil Dave Feb 05 '15 at 08:48
  • All Solution i tried not working anyone, when i do format as internal storage ... can you please me , how to do achieve this ? – Yogesh Rathi Jun 19 '19 at 08:10
  • closed as duplicate - newer post has answers up to Android R – Richard Le Mesurier Feb 01 '21 at 10:10
  • Perfect answer here https://stackoverflow.com/a/30401010/5773037 – Nikunj Paradva Jul 16 '21 at 08:31
  • @RichardLeMesurier why close the older as a duplicate of a newer? Stack Overflow is generally the reverse to minimise duplicates. (curious, not intending to insult you) – Andrew Kingdom Mar 02 '23 at 02:03
  • 1
    @AndrewKingdom The reason in my comment above. This post was less useful than the other post, since it was out of date (at least at the time) and did not include Android R. i.e. the code here was wrong. AFAIK the "duplicate" system is not about who posts first, but which post ends up being most useful. Obvs a moderator disagrees with me, and I see we now have duplicates again. – Richard Le Mesurier Mar 02 '23 at 07:46
  • For a post that addresses Android R, see this linked one: https://stackoverflow.com/questions/56663624/how-to-get-free-and-total-size-of-each-storagevolume – Richard Le Mesurier Mar 02 '23 at 07:47

14 Answers14

197

Below is the code for your purpose :

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

Get RAM Size

ActivityManager actManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
MemoryInfo memInfo = new ActivityManager.MemoryInfo();
actManager.getMemoryInfo(memInfo);
long totalMemory = memInfo.totalMem;
14wml
  • 4,048
  • 11
  • 49
  • 97
Dinesh Prajapati
  • 9,274
  • 5
  • 30
  • 47
  • and how to get RAM memory size ? how total and how in use ? – Gold Mar 26 '13 at 08:43
  • 2
    `getBlockSize()` and `getBlockCount` are deprecated. – Nima Nov 13 '13 at 20:50
  • 3
    @DineshPrajapati Thanks for the answer, I have query , If I use Environment.getRootDirectory() instead-of Environment.getDataDirectory for calculating Internal Storage, I am getting some output ..this refers to Internal Memory other memory.. – AK Joshi Apr 09 '14 at 05:36
  • Thank you so much, appreciate your help!! – swiftBoy Nov 20 '14 at 09:49
  • 3
    @DineshPrajapati .. Tested on MOTO G2 Getting wrong data for External Storage – AK Joshi Apr 08 '15 at 12:56
  • 1
    It may happen that couple of API's get deprecated, check out that on developers.android.com – Dinesh Prajapati Apr 09 '15 at 10:00
  • How would you also monitor the storage available size? – android developer May 22 '15 at 15:52
  • 1
    Use Long in the end for newer API levels(>18) – Gun2sh Jun 30 '15 at 07:13
  • to be more specific: use getBlockSizeLong() and getBlockCountLong() instead (API level >= 18) – Alexeev Valeriy Jul 19 '15 at 15:23
  • 1
    Thank you so much for sharing knowledge – Kishan Soni Aug 07 '15 at 13:42
  • didn't show size 0f External storage in motto g3 internal storage is showing but when it turns to sd_card it show same value for external storage as shows for internal pls tell @DineshPrajapati – Sunil Chaudhary May 04 '16 at 13:17
  • don't be confused with method externalMemoryAvailable(), it will return 'true' even if your device doesn't have any SD-card. (Nexus 5x for instance) this method is good for checking the state of the memory right now, is it available for read/write. It's a 'must have' check before any operations with storage – Kirill Karmazin Feb 15 '17 at 11:48
  • 1
    I feel duty bound to point out that there are 1000 bytes in a kilobyte and 1000 kilobytes in a megabyte. Android settings also gets this calculation wrong in the Storage tab. – Rupert Rawnsley Jun 07 '17 at 09:53
  • 1024 bytes = 1KB and 1024 KB = 1 MB – Dinesh Prajapati Oct 31 '17 at 17:26
  • Is there any permissions to be added to the newer Android version ?? – jeevan s Mar 10 '18 at 20:15
  • Here's my "localized" formatSize() version + GB's: (example: 1.172GB of 1.84GB) `{ double sizeInDouble = size; if (sizeInDouble >= 1024) { ...; if (sizeInDouble >= 1024) { ...; if (sizeInDouble >= 1024) { suffix = "GB"; sizeInDouble /= 1024; } } } NumberFormat nf = NumberFormat.getNumberInstance(Locale.getDefault()); DecimalFormat df = (DecimalFormat) nf; return df.format(sizeInDouble) + suffix; }` – Ben Aug 06 '18 at 12:38
  • Not Show Correct Total Intenrnal Memmory – Keshav Gera Feb 12 '19 at 10:39
  • 1
    @Keshav It's too old APIs hence there are chances that it's deprecated. – Dinesh Prajapati Feb 27 '19 at 05:32
  • Solution not working when i do format as internal storage ... can you please me , how to do achieve this – Yogesh Rathi Jun 19 '19 at 08:09
  • @YogeshRathi which portion of the code is not working? – Dinesh Prajapati Jul 01 '19 at 08:50
  • above code is working fine...in normal case, but if user select option adoptable storage then its not working,,,,just google format as internal storage option – Yogesh Rathi Jul 01 '19 at 09:40
42

This is the way I did it :

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);
Diederik
  • 5,536
  • 3
  • 44
  • 60
Android-Droid
  • 14,365
  • 41
  • 114
  • 185
31

Since API 9 you can do:

long freeBytesInternal = new File(ctx.getFilesDir().getAbsoluteFile().toString()).getFreeSpace();
long freeBytesExternal = new File(getExternalFilesDir(null).toString()).getFreeSpace();
Tzoiker
  • 1,354
  • 1
  • 14
  • 23
29

To get all available storage folders (including SD cards), you first get the storage files:

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

Then you can get the available size of each of those.

There are 3 ways to do it:

API 8 and below:

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

API 9 and above:

long availableSizeInBytes=file.getFreeSpace();

API 18 and above (not needed if previous one is ok) :

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

To get a nice formatted string of what you got now, you can use:

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

or you can use this in case you wish to see exact bytes number but nicely:

NumberFormat.getInstance().format(availableSizeInBytes);

Do note that I think the internal storage could be the same as the first external storage, since the first one is the emulated one.


EDIT: Using StorageVolume on Android Q and above, I think it's possible to get the free space of each, using something like:

fun getStorageVolumesAccessState(context: Context) {
    val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
    val storageVolumes = storageManager.storageVolumes
    val storageStatsManager = context.getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager
    for (storageVolume in storageVolumes) {
        var freeSpace: Long = 0L
        var totalSpace: Long = 0L
        val path = getPath(context, storageVolume)
        if (storageVolume.isPrimary) {
            totalSpace = storageStatsManager.getTotalBytes(StorageManager.UUID_DEFAULT)
            freeSpace = storageStatsManager.getFreeBytes(StorageManager.UUID_DEFAULT)
        } else if (path != null) {
            val file = File(path)
            freeSpace = file.freeSpace
            totalSpace = file.totalSpace
        }
        val usedSpace = totalSpace - freeSpace
        val freeSpaceStr = Formatter.formatFileSize(context, freeSpace)
        val totalSpaceStr = Formatter.formatFileSize(context, totalSpace)
        val usedSpaceStr = Formatter.formatFileSize(context, usedSpace)
        Log.d("AppLog", "${storageVolume.getDescription(context)} - path:$path total:$totalSpaceStr used:$usedSpaceStr free:$freeSpaceStr")
    }
}

fun getPath(context: Context, storageVolume: StorageVolume): String? {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
        storageVolume.directory?.absolutePath?.let { return it }
    try {
        return storageVolume.javaClass.getMethod("getPath").invoke(storageVolume) as String
    } catch (e: Exception) {
    }
    try {
        return (storageVolume.javaClass.getMethod("getPathFile").invoke(storageVolume) as File).absolutePath
    } catch (e: Exception) {
    }
    val extDirs = context.getExternalFilesDirs(null)
    for (extDir in extDirs) {
        val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
        val fileStorageVolume: StorageVolume = storageManager.getStorageVolume(extDir)
                ?: continue
        if (fileStorageVolume == storageVolume) {
            var file = extDir
            while (true) {
                val parent = file.parentFile ?: return file.absolutePath
                val parentStorageVolume = storageManager.getStorageVolume(parent)
                        ?: return file.absolutePath
                if (parentStorageVolume != storageVolume)
                    return file.absolutePath
                file = parent
            }
        }
    }
    try {
        val parcel = Parcel.obtain()
        storageVolume.writeToParcel(parcel, 0)
        parcel.setDataPosition(0)
        parcel.readString()
        return parcel.readString()
    } catch (e: Exception) {
    }
    return null
}

Hopefully this can help.

android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • 1
    How to get free space on removable SD card (or USB OTG flash drive) on devices with API 23? new StatFs(file.getPath()).getAvailableBytes() or file.getUsableSpace() gives 972546048 bytes regardless of real storage size on Nexus 5 (Marshmallow 6.0.1). – isabsent Feb 04 '16 at 17:23
  • @isabsent Nexus 5 doesn't have SD card slot. How did you check it? – android developer Feb 05 '16 at 12:56
  • I have checked it with USB OTG flash drive. – isabsent Feb 05 '16 at 16:24
  • @isabsent I never used it. Sorry. Does it work well on API 22 and below? – android developer Feb 05 '16 at 21:10
  • Yes, it works well up to 22. https://code.google.com/p/android/issues/detail?id=200326 – isabsent Feb 06 '16 at 04:34
  • @isabsent What about the other ways to get it? – android developer Feb 06 '16 at 12:53
  • I can't find other way to get it with File API or Storage Access Framework. I suppose it is possible with USB Host API http://developer.android.com/intl/ru/guide/topics/connectivity/usb/host.html – isabsent Feb 06 '16 at 13:48
  • @isabsent I can't find it there. – android developer Feb 06 '16 at 20:19
  • Take a look on getLength() in https://github.com/mjdev/libaums/blob/e3edc0eae2e5e32fc9f1c7a5ac1b9ac18a40a421/libaums/src/main/java/com/github/mjdev/libaums/fs/fat32/FatFile.java – isabsent Feb 06 '16 at 23:44
  • What does it mean - "CTOR"? Constructor? – isabsent Feb 07 '16 at 06:46
  • @isabsent Yes. CTOR is Constructor. – android developer Feb 07 '16 at 08:29
  • File[] externalStorageFiles=ContextCompat.getExternalFilesDirs(this,null); this line gives me the output "/storage/sdcard0/Android/data/com.demo.memorycarddemo/files" and it has only one element at 0 index while I have removable sdcard mounted on the device. Can you please help me to find out the path of removable sdcard ? – Smeet Mar 19 '16 at 20:03
  • 1
    @Smeet Is it possible you try it on Android 6 or above? If so, maybe it's an issue like this: https://code.google.com/p/android/issues/detail?id=200326 – android developer Mar 19 '16 at 20:13
  • @androiddeveloper Yes I am currently reading that same thread but not able to find out the solution of it. Android 6.0 has this issue but this code is even not working in 4.4.2. Currently I am testing it in 4.4.2 Is it working fine below Android 6.0? – Smeet Mar 19 '16 at 20:16
  • @Smeet It's supposed to. Sure you've added the correct permissions? Only starting with Kitkat, it should provide you both paths without permissions : http://developer.android.com/intl/ru/reference/android/support/v4/content/ContextCompat.html#getExternalFilesDirs(android.content.Context, java.lang.String) . If it's not, it's a bug. Please post an issue, and I will star it. – android developer Mar 19 '16 at 20:56
  • @androiddeveloper Really thank you so much for your reply and co-ordination. I read that entire google discussion thread and many developers posted really great suggestions and since new 6.0 API, there are lots of thing changed and due to this we are facing lots of issues. I have posted the working code at http://stackoverflow.com/questions/8133417/android-get-free-size-of-internal-external-memory/36110514#36110514 and at https://code.google.com/p/android/issues/detail?id=200326 – Smeet Mar 20 '16 at 05:27
  • @androiddeveloper If you have US OTG then can you please check it and let me know if it is working fine or not? Actually it was not a permission issue but ContextCompat.getExternalFilesDirs(this,null) gives me only phone's external storage path and not removable storage path. Not sure what was the issue. So I ended up with above solution. – Smeet Mar 20 '16 at 05:29
  • need difference between `.getFreeSpace()` and `.getAvailableSize()` , i have seen case first one gives 11mb and latter one gives 405kb – Jemshit Nov 17 '16 at 14:19
  • getAvailableBytes() – Jemshit Nov 18 '16 at 04:38
  • @JemshitIskenderov Well, this is odd. So which is the correct one? And in which cases you noticed it? Maybe you should report this as a bug here: https://code.google.com/p/android/issues/ – android developer Nov 18 '16 at 06:27
  • getFreeSpace was more likely, but getAvailableBytes gives space that apps can use i think – Jemshit Nov 18 '16 at 06:29
  • @JemshitIskenderov If you can find a scenario that they are different, and can reproduce it, please file a bug report here: https://code.google.com/p/android/issues/ , and I will star it too. – android developer Nov 20 '16 at 06:10
  • Since nowadays API 19 and above needs to be supported for almost 95%+ devices, I would suggest using StatFs and the Formatter as mentioned in the answer. I was getting wrong result when parsing it to human form by "1024" logic, but Fomatter worked like a charm. – Ankit Bansal Oct 12 '18 at 12:49
  • Solution not working when i do format as internal storage ... can you please me , how to do achieve this – Yogesh Rathi Jun 19 '19 at 08:09
  • @YogeshRathi Which solution, and what are you trying to do? Have you asked about it somewhere? If so, please show a link. – android developer Jun 19 '19 at 08:39
  • https://stackoverflow.com/questions/39784846/how-to-calculate-free-memory-on-android-when-sd-card-is-formatted-as-internal-on#comment99894285_39784846 – Yogesh Rathi Jun 19 '19 at 09:17
  • If people ask a quastion java code, at least have the decency to reply in java. No sane person uses kotlin – CaptainCrunch Apr 06 '22 at 16:01
9

@Android-Droid - you are wrong Environment.getExternalStorageDirectory() points to external storage which does not have to be SD card, it can also be mount of internal memory. See:

Find an external SD card location

Community
  • 1
  • 1
Sharp80
  • 186
  • 2
  • 4
8

Try this simple snippet

    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
  • 2,008
  • 24
  • 18
  • Thanks, but I have the `java.lang.ArrayIndexOutOfBoundsException: length=5; index=-2147483648` error, seems that `digitGroups` result is -2147483648. – Acuna Apr 16 '18 at 19:55
  • Solution not working when i do format as internal storage ... can you please me , how to do achieve this – Yogesh Rathi Jun 19 '19 at 08:10
6

It is very easy to find out the storage available if you get internal as well as external storage path. Also phone's external storage path really very easy to find out using

Environment.getExternalStorageDirectory().getPath();

So I am just concentrating on how to find out the paths of external removable storage like removable sdcard, USB OTG(not tested USB OTG as I have no USB OTG).

Below method will give a list of all possible external removable storage paths.

 /**
     * 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
  • 4,036
  • 1
  • 36
  • 47
  • As I remember, using constant names for paths handling might not work on some devices, as some might have their own paths. I hope this is not the case. +1 for the effort. – android developer Mar 20 '16 at 07:47
  • 1
    @androiddeveloper Thank you dear for up voting. I need support of all to test this code in your device because I don't have all devices but tested in 4 different devices and working fine. Please comment here is not working in any body's mobile. – Smeet Mar 21 '16 at 04:55
  • Solution not working when i do format as internal storage ... can you please me , how to do achieve this – Yogesh Rathi Jun 19 '19 at 08:09
5

Quick addition to External memory topic

Don't be confused by the method name externalMemoryAvailable() in Dinesh Prajapati's answer.

Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) gives you the current state of the memory, if the media is present and mounted at its mount point with read/write access. You will get true even on devices with no SD-cards, like Nexus 5. But still it's a 'must-have' method before any operations with storage.

To check if there is an SD-card on your device you can use method ContextCompat.getExternalFilesDirs()

It doesn't show transient devices, such as USB flash drives.

Also be aware that ContextCompat.getExternalFilesDirs() on Android 4.3 and lower will always return only 1 entry (SD-card if it's available, otherwise Internal). You can read more about it here.

  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;
}

in my case it was enough, but don't forget that some of the Android devices might have 2 SD-cards, so if you need all of them - adjust the code above.

Kirill Karmazin
  • 6,256
  • 2
  • 54
  • 42
5

This is the way i did it..

internal Total memory

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

Internal free size

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

External free and total memory

 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";
Community
  • 1
  • 1
makvine
  • 119
  • 2
  • 4
  • 4
    Your method shows that I have 29 GB free out of a total of 50 GB. However, my standard files app (Huawei P20 Lite) and the files app from Google show 32 GB free out of a total of 64 GB. Am I missing something or does your method exclude something from the storage? – Danny E.K. van der Kolk Jan 29 '21 at 23:24
5

None of the solutions mentioned here can be used for External Memory. Here is my code(for RAM, ROM, System Storage and External Storage). You can calculate free storage by using (total storage - used storage). And also, one must not use Environment.getExternalStorageDirectory() for external storage. It does not necessarily points to External SD Card. Also, this solution will work with all the Android versions (tested for API 16-30 on real devices and emulators).

    // Divide by (1024*1024*1024) to get in GB, by (1024*1024) to get in MB, by 1024 to get in KB..

    // RAM
    ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    manager.getMemoryInfo(memoryInfo);
    long totalRAM=memoryInfo.totalMem;
    long availRAM=memoryInfo.availMem;  // remember to convert in GB,MB or KB.
    long usedRAM=totalRAM-availRAM;

    // ROM
    getTotalStorageInfo(Environment.getDataDirectory().getPath());
    getUsedStorageInfo(Environment.getDataDirectory().getPath());

    // System Storage
    getTotalStorageInfo(Environment.getRootDirectory().getPath());
    getUsedStorageInfo(Environment.getRootDirectory().getPath());

    // External Storage (SD Card)
    File[] files = ContextCompat.getExternalFilesDirs(context, null);
    if(Build.VERSION.SDK_INT<=Build.VERSION_CODES.JELLY_BEAN_MR2){
        if (files.length == 1) {
            Log.d("External Storage Memory","is present");
            getTotalStorageInfo(files[0].getPath());
            getUsedStorageInfo(files[0].getPath());
        }
    } else {
        if (files.length > 1 && files[0] != null && files[1] != null) {
            Log.d("External Storage Memory","is present");
            long t=getTotalStorageInfo(files[1].getPath());
            long u=getUsedStorageInfo(files[1].getPath());
            System.out.println("Total External Mem: "+t+" Used External Mem: "+u+" Storage path: "+files[1].getPath());
        }
    }
}

public long getTotalStorageInfo(String path) {
    StatFs statFs = new StatFs(path);
    long t;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
        t = statFs.getTotalBytes();
    } else {
        t = statFs.getBlockCount() * statFs.getBlockSize();
    }
    return t;    // remember to convert in GB,MB or KB.
}

public long getUsedStorageInfo(String path) {
    StatFs statFs = new StatFs(path);
    long u;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
        u = statFs.getTotalBytes() - statFs.getAvailableBytes();
    } else {
        u = statFs.getBlockCount() * statFs.getBlockSize() - statFs.getAvailableBlocks() * statFs.getBlockSize();
    }
    return u;  // remember to convert in GB,MB or KB.
}

Now here for ROM I have used path as "/data" and for System Storage path is "/system". And for External Storage I have used ContextCompat.getExternalFilesDirs(context, null); therefore it will work on Android Q and Android R also. I hope, this will help you.

Mrudul Tora
  • 715
  • 8
  • 14
4
@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
        }
    }
}

StorageStatsManager class introduced Android O and above which can give you free and total byte in external/internal storage. For detailed with source code, you can read my following article. you can use reflection for lower than Android O

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

Brijesh Gupta
  • 487
  • 4
  • 8
  • Yes! This works, and shows the exact amount of total and free space on my internal storage (Huawei P20 Lite). Thank you for saving me a lot of headaches! – Danny E.K. van der Kolk Jan 29 '21 at 23:33
  • 1
    It works great except that some phones return the short UUID string representation that does not work with UUID.fromString(uuidStr). To get other this situation you can use: UUID.nameUUIDFromBytes(storageVolume.getUuid().getBytes()); instead – user1060873 Mar 23 '22 at 02:16
1

After checking different solution write code myself this is complete code for finding

  • Total External Memory
  • Free External Memory
  • Used External Memory
  • TotaL Internal Memory
  • Used Internal Memory
  • Free Internal Memory

''''

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
  • 609
  • 8
  • 6
1

You can do this like that:

fun getFreeSpaceMB(): Long {
    val stat = StatFs(Environment.getExternalStorageDirectory().path)
    return stat.availableBytes / (1024 * 1024)
}
Igor Konyukhov
  • 394
  • 4
  • 7
0

About external menory ,there is another way:
File external = Environment.getExternalStorageDirectory(); free:external.getFreeSpace(); total:external.getTotalSpace();