Android Read Write External Storage File Example

Android storage can be divided into two types, internal storage, and external storage. This article will introduce both internal and external storage and how to use them to save files in your android application.

1. Android Internal Storage Overview.

Internal storage is used to store android app private data such as files, cached files, shared_preferences, and database files. All those files are stored in the android device folder /data/data/< app package name>/. And only the android app can operate those files. In general internal storage stored files are saved in android device build-in flash disk memory.

1.1 Browse Android Internal Storage Folder And Files.

We can use an android device monitor to browse the android internal storage directory. Generally, internal storage is not allowed to be accessed by others, so we should run the below commands in the dos window to change the directory access permission.

C:\Users\Jerry>adb shell
generic_x86:/ $ su
generic_x86:/ # chmod 777 /data
generic_x86:/ # chmod 777 /data/data
generic_x86:/ # chmod 777 /data/data/com.dev2qa.example/
generic_x86:/ # chmod 777 /data/data/com.dev2qa.example/files/
generic_x86:/ # chmod 777 /data/data/com.dev2qa.example/cache/
generic_x86:/ # chmod 777 /data/data/com.dev2qa.example/shared_prefs/
generic_x86:/ # chmod 777 /data/data/com.dev2qa.example/databases/

Then click Tools —> Android —> Android Device Monitor to open it to browse above internal storage folders as below. Please read the article Android Device Monitor Cannot Open Data Folder Resolve Method to learn more.

android-internal-storage-folders

 

1.2 Internal Storage Summary.

  1. Can be accessed by android apps only.
  2. When an android app is uninstalled, all those folders will be removed also.
  3. Internal storage folders location is /data/data/< app package name>/

Reference Articles.

  1. Android ADB Install / Uninstall App Examples
  2. Android Read Write Internal Storage File Example
  3. Android Shared Preferences Example
  4. Android SQLite Database Introduction
  5. How To Show Data From SQLite Database In Android ListView

2. Android External Storage Overview.

Android external storage can store files in an SD card or device build-in flash disk memory. Internal and external is only a logical classification. There are two types of android external storage folders. They are both saved in /storage/emulated/0 directory. But in some android devices, they will be stored in /mnt or /sdcard folder, etc.

android-external-storage-folders

 

  1. Public External Storage Directory: In the above picture, directory Alarms, DCIM, Download, Movies, Music, Notifications, and Pictures are public external storage folders. They can be accessed by all android app. And when an android app is uninstalled, the files saved in those public folders will not be removed.
    // Get public external storage folder ( /storage/emulated/0 ). 
    File externalDir = Environment.getExternalStorageDirectory();
    
    // Get /storage/emulated/0/Music folder.
    File musicPublicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
  2. App Specific ( Private ) External Storage Folder: This kind of folder is used to store android app private files. When the app is uninstalled, the files in these private folders will be removed also.
    In above picture, app private external storage directory is /storage/emulated/0/Android/data/< app package name>/.

    // Return folder /storage/emulated/0/Android/data/com.dev2qa.example/files
    File privateDir = context.getExternalFilesDir(null);
    
    // Return folder /storage/emulated/0/Android/data/com.dev2qa.example/files/Music
    File musicPrivateDir = context.getExternalFilesDir(Environment.DIRECTORY_MUSIC);
    
    // Create and return folder /storage/emulated/0/Android/data/com.dev2qa.example/files/Custom
    File customPrivateDir = context.getExternalFilesDir("Custom");
    
    // Return folder /storage/emulated/0/Android/data/com.dev2qa.example/cache
    File cachedPrivateDir = context.getExternalCacheDir();

3. Android External Storage Required Permissions.

Run below shell command in a dos window, you can see that the /storage/emulated folder belongs to sdcard_rw group, this means before your app can manipulate the external storage directory, you should grant write permission to it.

C:\Users\Jerry>adb shell
generic_x86:/ # su
generic_x86:/ # cd /storage/
generic_x86:/storage # ls -l
total 9
drwxrwx--x 4 root sdcard_rw 512 1970-01-01 00:00 0B0E-2405
drwx--x--x 4 root sdcard_rw 4096 2018-01-05 03:46 emulated
drwxr-xr-x 2 root root 60 2018-01-21 11:20 self
generic_x86:/storage #

To grant external storage read-write permission, you need first declare the below permissions in AndroidManifest.xml file.

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

If you use an android OS version bigger than 6.0, you also need to require the above two external storage permissions at run time in your java code as below.

// Check whether this app has write external storage permission or not.
int writeExternalStoragePermission = ContextCompat.checkSelfPermission(ExternalStorageActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
// If do not grant write external storage permission.
if(writeExternalStoragePermission!= PackageManager.PERMISSION_GRANTED)
{
    // Request user to grant write external storage permission.
    ActivityCompat.requestPermissions(ExternalStorageActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION);
}

When the program executes the above code, android will popup a confirm dialog which lets you allow or deny the required permissions.

When you click the allow or deny button, the below method will be invoked, you can show Toast messages in it.

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if(requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION)
    {
        int grantResultsLength = grantResults.length;
        if(grantResultsLength > 0 && grantResults[0]==PackageManager.PERMISSION_GRANTED)
        {
            Toast.makeText(getApplicationContext(), "You grant write external storage permission. Please click original button again to continue.", Toast.LENGTH_LONG).show();
        }else
        {
            Toast.makeText(getApplicationContext(), "You denied write external storage permission.", Toast.LENGTH_LONG).show();
        }
    }

If you do not grant the above two permissions, your read-write external storage java code will throw below exception.

java.io.FileNotFoundException: /storage/emulated/0/DCIM/abc.txt (Permission denied)

write-external-storage-permission-denied-error

 

4. Android External Storage Read Write File Example.

 

4.1 Main Activity Java File.

ExternalStorageActivity.java

package com.dev2qa.example.storage.external;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.dev2qa.example.R;

import java.io.File;
import java.io.FileWriter;

import static com.dev2qa.example.storage.external.ExternalStorageUtil.getPrivateExternalStorageBaseDir;

public class ExternalStorageActivity extends AppCompatActivity {

    private static final String LOG_TAG_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";

    private static final int REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_external_storage);

        setTitle("dev2qa.com - Android External Storage Example.");

        final EditText emailEditor = (EditText)findViewById(R.id.external_storage_editor_email);

        // Save email to a public external storage folder.
        Button savePublicExternalStorageButton = (Button)findViewById(R.id.external_storage_button_save_public);
        savePublicExternalStorageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                try {
                    if(ExternalStorageUtil.isExternalStorageMounted()) {

                        // Check whether this app has write external storage permission or not.
                        int writeExternalStoragePermission = ContextCompat.checkSelfPermission(ExternalStorageActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
                        // If do not grant write external storage permission.
                        if(writeExternalStoragePermission!= PackageManager.PERMISSION_GRANTED)
                        {
                            // Request user to grant write external storage permission.
                            ActivityCompat.requestPermissions(ExternalStorageActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION);
                        }else {

                            // Save email_public.txt file to /storage/emulated/0/DCIM folder
                            String publicDcimDirPath = ExternalStorageUtil.getPublicExternalStorageBaseDir(Environment.DIRECTORY_DCIM);

                            File newFile = new File(publicDcimDirPath, "email_public.txt");

                            FileWriter fw = new FileWriter(newFile);

                            fw.write(emailEditor.getText().toString());

                            fw.flush();

                            fw.close();

                            Toast.makeText(getApplicationContext(), "Save to public external storage success. File Path " + newFile.getAbsolutePath(), Toast.LENGTH_LONG).show();
                        }
                    }

                }catch (Exception ex)
                {
                    Log.e(LOG_TAG_EXTERNAL_STORAGE, ex.getMessage(), ex);

                    Toast.makeText(getApplicationContext(), "Save to public external storage failed. Error message is " + ex.getMessage(), Toast.LENGTH_LONG).show();
                }
            }
        });

        // Save email to a app private external storage folder.
        Button savePrivateExternalStorageButton = (Button)findViewById(R.id.external_storage_button_save_private);
        savePrivateExternalStorageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                try {
                    if(ExternalStorageUtil.isExternalStorageMounted()) {

                        // Check whether this app has write external storage permission or not.
                        int writeExternalStoragePermission = ContextCompat.checkSelfPermission(ExternalStorageActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
                        // If do not grant write external storage permission.
                        if(writeExternalStoragePermission!= PackageManager.PERMISSION_GRANTED)
                        {
                            // Request user to grant write external storage permission.
                            ActivityCompat.requestPermissions(ExternalStorageActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION);
                        }else {

                            // Save email_private.txt file to /storage/emulated/0/Android/data/com.dev2qa.example/files folder
                            String privateDirPath = getPrivateExternalStorageBaseDir(getApplicationContext(), null);

                            File newFile = new File(privateDirPath, "email_private.txt");

                            FileWriter fw = new FileWriter(newFile);

                            fw.write(emailEditor.getText().toString());

                            fw.flush();

                            fw.close();

                            Toast.makeText(getApplicationContext(), "Save to private external storage success. File Path " + newFile.getAbsolutePath(), Toast.LENGTH_LONG).show();
                        }
                    }

                }catch (Exception ex)
                {
                    Log.e(LOG_TAG_EXTERNAL_STORAGE, ex.getMessage(), ex);

                    Toast.makeText(getApplicationContext(), "Save to private external storage failed. Error message is " + ex.getMessage(), Toast.LENGTH_LONG).show();
                }
            }
        });

        // Save email to a app private cached external storage folder.
        Button savePrivateCachedExternalStorageButton = (Button)findViewById(R.id.external_storage_button_save_private_cache);
        savePrivateCachedExternalStorageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                try {
                    if(ExternalStorageUtil.isExternalStorageMounted()) {

                        // Check whether this app has write external storage permission or not.
                        int writeExternalStoragePermission = ContextCompat.checkSelfPermission(ExternalStorageActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
                        // If do not grant write external storage permission.
                        if(writeExternalStoragePermission!= PackageManager.PERMISSION_GRANTED)
                        {
                            // Request user to grant write external storage permission.
                            ActivityCompat.requestPermissions(ExternalStorageActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION);
                        }else {

                            // Save email_private_cache.txt file to /storage/emulated/0/Android/data/com.dev2qa.example/cache folder
                            String privateDirPath = ExternalStorageUtil.getPrivateCacheExternalStorageBaseDir(getApplicationContext());

                            File newFile = new File(privateDirPath, "email_private_cache.txt");

                            FileWriter fw = new FileWriter(newFile);

                            fw.write(emailEditor.getText().toString());

                            fw.flush();

                            fw.close();

                            Toast.makeText(getApplicationContext(), "Save to private external storage success. File Path " + newFile.getAbsolutePath(), Toast.LENGTH_LONG).show();
                        }
                    }

                }catch (Exception ex)
                {
                    Log.e(LOG_TAG_EXTERNAL_STORAGE, ex.getMessage(), ex);

                    Toast.makeText(getApplicationContext(), "Save to private external storage failed. Error message is " + ex.getMessage(), Toast.LENGTH_LONG).show();
                }
            }
        });

        // Display private and public external storage directory in android monitor logcat console.
        Button displayExternalStoragePathButton = (Button)findViewById(R.id.external_storage_button_display_path);
        displayExternalStoragePathButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                // Because create custom directory in public external storage folder need write permission
                // So we should grant the permission to the app first.

                // Check whether this app has write external storage permission or not.
                int writeExternalStoragePermission = ContextCompat.checkSelfPermission(ExternalStorageActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
                // If do not grant write external storage permission.
                if(writeExternalStoragePermission!= PackageManager.PERMISSION_GRANTED)
                {
                    // Request user to grant write external storage permission.
                    ActivityCompat.requestPermissions(ExternalStorageActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION);
                }else {
                    Log.d(LOG_TAG_EXTERNAL_STORAGE, "Below are public external storage folder path.");

                    // Use Environment class to get public external storage directory.
                    File publicDir = Environment.getExternalStorageDirectory();
                    Log.d(LOG_TAG_EXTERNAL_STORAGE, "Environment.getExternalStorageDirectory() : " + publicDir.getAbsolutePath());

                    // Because at the beginning of this method, we had grant write external storage permission
                    // So we can create this directory here.
                    File customPublicDir = new File(publicDir, "Custom");
                    customPublicDir.mkdirs();
                    Log.d(LOG_TAG_EXTERNAL_STORAGE, "Create custom dir : " + customPublicDir.getAbsolutePath());

                    File musicPublicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
                    Log.d(LOG_TAG_EXTERNAL_STORAGE, "Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC) : " + musicPublicDir.getAbsolutePath());

                    File dcimPublicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
                    Log.d(LOG_TAG_EXTERNAL_STORAGE, "Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) : " + dcimPublicDir.getAbsolutePath());

                    Log.d(LOG_TAG_EXTERNAL_STORAGE, "**********************************************************************");

                    Log.d(LOG_TAG_EXTERNAL_STORAGE, "Below are android app private external storage folder path.");

                    // Use Context class to get app private external storage directory

                    Context context = getApplicationContext();

                    File privateDir = context.getExternalFilesDir(null);
                    Log.d(LOG_TAG_EXTERNAL_STORAGE, "context.getExternalFilesDir(null) : " + privateDir.getAbsolutePath());

                    File musicPrivateDir = context.getExternalFilesDir(Environment.DIRECTORY_MUSIC);
                    Log.d(LOG_TAG_EXTERNAL_STORAGE, "context.getExternalFilesDir(Environment.DIRECTORY_MUSIC) : " + musicPrivateDir.getAbsolutePath());

                    File dcimPrivateDir = context.getExternalFilesDir(Environment.DIRECTORY_DCIM);
                    Log.d(LOG_TAG_EXTERNAL_STORAGE, "context.getExternalFilesDir(Environment.DIRECTORY_DCIM) : " + dcimPrivateDir.getAbsolutePath());

                    File customPrivateDir = context.getExternalFilesDir("Custom");
                    Log.d(LOG_TAG_EXTERNAL_STORAGE, "context.getExternalFilesDir(\"Custom\") : " + customPrivateDir.getAbsolutePath());

                    File cachedPrivateDir = context.getExternalCacheDir();
                    Log.d(LOG_TAG_EXTERNAL_STORAGE, "context.getExternalCacheDir() : " + cachedPrivateDir.getAbsolutePath());

                    Toast.makeText(context, "Please see the output in android monitor logcat console.", Toast.LENGTH_LONG).show();
                }

            }
        });
    }

    // This method is invoked after user click buttons in permission grant popup dialog.
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if(requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION)
        {
            int grantResultsLength = grantResults.length;
            if(grantResultsLength > 0 && grantResults[0]==PackageManager.PERMISSION_GRANTED)
            {
                Toast.makeText(getApplicationContext(), "You grant write external storage permission. Please click original button again to continue.", Toast.LENGTH_LONG).show();
            }else
            {
                Toast.makeText(getApplicationContext(), "You denied write external storage permission.", Toast.LENGTH_LONG).show();
            }
        }
    }
}

4.2 Main Layout Xml File.

activity_external_storage.xml

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <EditText
        android:id="@+id/external_storage_editor_email"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Input your email."/>

    <Button
        android:id="@+id/external_storage_button_save_public"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Save To Public External Storage"/>

    <Button
        android:id="@+id/external_storage_button_save_private"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Save To Private External Storage"/>

    <Button
        android:id="@+id/external_storage_button_save_private_cache"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Save To Private Cached External Storage"/>

    <Button
        android:id="@+id/external_storage_button_display_path"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Display External Storage Directory Path"/>

</LinearLayout>

4.3 Android External Storage Util Tool Java File.

ExternalStorageUtil.java

package com.dev2qa.example.storage.external;

import android.content.Context;
import android.os.Environment;
import android.os.StatFs;

import java.io.File;

/**
 * Created by Jerry on 1/22/2018.
 */

public class ExternalStorageUtil {

    // Check whether the external storage is mounted or not.
    public static boolean isExternalStorageMounted() {

        String dirState = Environment.getExternalStorageState();
        if(Environment.MEDIA_MOUNTED.equals(dirState))
        {
            return true;
        }else
        {
            return false;
        }
    }

    // Check whether the external storage is read only or not.
    public static boolean isExternalStorageReadOnly() {

        String dirState = Environment.getExternalStorageState();
        if(Environment.MEDIA_MOUNTED_READ_ONLY.equals(dirState))
        {
            return true;
        }else
        {
            return false;
        }
    }


    // Get private external storage base directory.
    public static String getPrivateExternalStorageBaseDir(Context context, String dirType)
    {
        String ret = "";
        if(isExternalStorageMounted()) {
            File file = context.getExternalFilesDir(dirType);
            ret = file.getAbsolutePath();
        }
        return ret;
    }

    // Get private cache external storage base directory.
    public static String getPrivateCacheExternalStorageBaseDir(Context context)
    {
        String ret = "";
        if(isExternalStorageMounted()) {
            File file = context.getExternalCacheDir();
            ret = file.getAbsolutePath();
        }
        return ret;
    }


    // Get public external storage base directory.
    public static String getPublicExternalStorageBaseDir()
    {
        String ret = "";
        if(isExternalStorageMounted()) {
            File file = Environment.getExternalStorageDirectory();
            ret = file.getAbsolutePath();
        }
        return ret;
    }

    // Get public external storage base directory.
    public static String getPublicExternalStorageBaseDir(String dirType)
    {
        String ret = "";
        if(isExternalStorageMounted()) {
            File file = Environment.getExternalStoragePublicDirectory(dirType);
            ret = file.getAbsolutePath();
        }
        return ret;
    }

    // Get external storage disk space, return MB
    public static long getExternalStorageSpace() {
        long ret = 0;
        if (isExternalStorageMounted()) {
            StatFs fileState = new StatFs(getPublicExternalStorageBaseDir());

            // Get total block count.
            long count = fileState.getBlockCountLong();

            // Get each block size.
            long size = fileState.getBlockSizeLong();

            // Calculate total space size
            ret = count * size / 1024 / 1024;
        }
        return ret;
    }

    // Get external storage left free disk space, return MB
    public static long getExternalStorageLeftSpace() {
        long ret = 0;
        if (isExternalStorageMounted()) {
            StatFs fileState = new StatFs(getPublicExternalStorageBaseDir());

            // Get free block count.
            long count = fileState.getFreeBlocksLong();

            // Get each block size.
            long size = fileState.getBlockSizeLong();

            // Calculate free space size
            ret = count * size / 1024 / 1024;
        }
        return ret;
    }

    // Get external storage available disk space, return MB
    public static long getExternalStorageAvailableSpace() {
        long ret = 0;
        if (isExternalStorageMounted()) {
            StatFs fileState = new StatFs(getPublicExternalStorageBaseDir());

            // Get available block count.
            long count = fileState.getAvailableBlocksLong();

            // Get each block size.
            long size = fileState.getBlockSizeLong();

            // Calculate available space size
            ret = count * size / 1024 / 1024;
        }
        return ret;
    }
}

6 thoughts on “Android Read Write External Storage File Example”

  1. I would like to suggest you, try LongPathTool program to resolve this issue.
    This tool is very helpful to resolve the issue.

  2. Jerry,

    Great example.
    Could you explain a bit more about su followed by adb shell.
    my understanding is that su commands can only be executed on rooted phone?

  3. Please get WordPress to display your article in a wider column. On my screen the article only takes up 1/3 of the width of my monitor space.

    The code snippets in the boxes end up require scrolling to the right and back to see the whole example.

    I ended up copy and pasting the snippets into a text editor for better examination.

  4. I found your article much much useful than all other article which i found in internet till day, you have elaborated and explained neatly everything that kept me to read whole article till end..

    I came across your article to know how to get path or location address of memorycard which is inserted to android like pendrive or memorycard of 32 or 64gb(samsung,sandisk) where i want to store my app public data.

    I dont find any article in internet till day, if you know how to access memorycard path which is inserted to android mobile email me or post a article which helps developers to find a way to access it..

    you can personally email me if you know a solution for this which helps me for research i am doing thank you.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.