3

My Samsung X-Cover2 GT-S7710 with a 32GB SD card reports correct space in Settings>Storage, but only 0.6 GB with this code or How can I check how much free space an SD card mounted on an Android device has?:

sdStorageDirectory = Environment.getExternalStorageDirectory().getPath();
StatFs statSd = new StatFs(sdStorageDirectory);
Log.d(TAG, "gb available " + String.valueOf((double) (statSd.getAvailableBlocks() * statSd.getBlockSize()) / 1073741824));

Why is this, and how can I discover the true free space correctly?

Community
  • 1
  • 1
ajayel
  • 3,027
  • 2
  • 26
  • 33
  • what's your question? – cbrulak Jun 20 '13 at 00:53
  • Related question: http://stackoverflow.com/questions/15521050/how-read-and-display-available-space-in-android-both-sd-card-and-internal-memory – aug Jun 23 '13 at 23:18
  • It's possible that the SD card is not being used as the Android API "External Storage" but rather as some additional volume with vendor-unique handling. – Chris Stratton Jun 24 '13 at 01:00

2 Answers2

3

The reason for this behaviour is probably that in the case of your phone the SD card is not considered the main external storage device. The description of getExternalStorageDirectory() explains this:

Note: don't be confused by the word "external" here. This directory can better be thought as media/shared storage. It is a filesystem that can hold a relatively large amount of data and that is shared across all applications (does not enforce permissions). Traditionally this is an SD card, but it may also be implemented as built-in storage in a device that is distinct from the protected internal storage and can be mounted as a filesystem on a computer.

So you're probably getting some other system that really is 0.6 GB big.

Luckily, chances are pretty high that the device you're looking for is mounted in the same parent directory as the one you're getting. So first of all, I'd check whether this is the device you're looking for with something like isExternalStorageRemovable() and if not so, try other devices in the same parent directory:

File sdStorage;
if(sdStorage.isExternalStorageRemovable()) {
     sdStorage = Environment.getExternalStorageDirectory();
} else {
    List<File> storages = Environment.getExternalStorageDirectory().getParentFile().listFiles();
    for(File storage : storages) {
        if(! storages.equals(Environment.getExternalStorageDirectory()) {
            sdStorage = storage;
            break;
        }
    }
}
if(sdStorage == null) {
    // No non-removable storage device was found
}

This asumes, that there are only two devices mounted. In some rare cases, this may not be true (e.g. because a further storage device is mounted via USB-OTG); you'll have to find another workaround here. One idea may be to run the mount command which is described here via a process and work through those results to find the correct device. This however will become quite complicated. It also asumes that all external storage devices are mounted under the same parent directory (usually /mnt/). If that isn't the case the mount command is once again your best hope.

EDIT 1: There might be some devices which mount to /sdcard without using the /mnt directory (though that might in some cases be a reference to /mnt/sdcard in which case you'll be fine). So in those cases you'll have to use the output of mount.

EDIT 2: I checked and found, that on my phone the /mnt contains quite a few directories and I only want one of those. So I came up with this solution instead of the one above:

File sdStorage;
if(sdStorage.isExternalStorageRemovable()) {
     sdStorage = Environment.getExternalStorageDirectory();
} else {
    Process process = null;
    Scanner scan = null;
    try {
        process = new ProcessBuilder().command("ls", "-l", sdStorage.getParent()).redirectErrorStream(true).start();
        scan = new Scanner(process.getInputStream());
        while(scan.hasNextLine()) {
            String line = scan.nextLine();
            String[] parts = line.split("\\s");
            if(parts.length > 2 && parts[2].equals("sdcard_rw") 
              && ! Environment.getExternalStorageDirectory().equals(Environment.getExternalStorageDirectory().getParent() + File.seperator + parts[3]) {
                sdStorage = new File(Environment.getExternalStorageDirectory().getParent() + File.seperator + parts[3]);
                break;
            }
        } catch(IOException e) {
            // Do something here
        } finally {
            if(scan != null)
                scan.close();
            if(process != null)
                process.destroy();
        }
    }
}

The background here is, that all external storage devices seem to belong to the user sdcard_rw so this is what we can check for. Sadly the shortest method to check a files ownership within Android seems to be... Well, not very intuitive. But hopefully, this should work indepently of where exactly the various storage devices are mounted.

blalasaadri
  • 5,990
  • 5
  • 38
  • 58
  • I am facing the same issue can you please help, when I try to use the above code. I am getting an error "Error:(133, 76) error: variable sdStorage might not have been initialized". – Hari Swaminathan Sep 07 '16 at 07:37
  • I just checked and, although it's been a while, I think the problem is pretty easy to solve. In the first if statement, replace "sdStorage.isExternalStorageRemovable()" with "Environment.isExternalStorageRemovable()". Because "sdStorage" has at that point indeed not been initialized. – blalasaadri Sep 07 '16 at 07:45
  • I have replaced the if statement "sdStorage" as you suggestedlike "if (android.os.Environment.isExternalStorageRemovable())". But the same error is now on this line process = new ProcessBuilder().command("ls", "-l", sdStorage.getParent()).redirectErrorStream(true).start(); – Hari Swaminathan Sep 07 '16 at 08:01
  • Again, we're accessing that variable that indeed has not been initialized yet. I'll have to try something out, but I guess initializing sdStorage with the value from the if clause may help. It will be changed later of course. – blalasaadri Sep 07 '16 at 08:14
1

Try this:

StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
long bytesAvailable = (long)stat.getBlockSize() *(long)stat.getBlockCount();
long megAvailable = bytesAvailable / 1048576;
System.out.println("Megs :"+megAvailable);

getBlockCount() - return size of SD card; getAvailableBlocks() - return the number of blocks that are still accessible to normal programs

Details in this link

Community
  • 1
  • 1
Has AlTaiar
  • 4,052
  • 2
  • 36
  • 37