Android External Storage Tutorial

1- Android External Storage

Android External Storage: a place to store addition data  of Android, the files that you store here is not applied the security system.

Usually there are two types of external storage: 
  1. Fixed external storage: Commonly understood as the hard drive of the device.
  2. Removable  storage: Such as SD Card. 
Use the static method of Environment class  you can get the information on the directory of the external storage.
The table below results running on the emulator device.
Method Returns
getDataDirectory() /data
getDownloadCacheDirectory() /cache
getExternalStorageState() mounted
getExternalStoragePublicDirectory(Environment.Music): /storage/emulated/0/Music
getDownloadCacheDirectory() /cache
getRootDirectory() /system
To read/write the data on the external storage requires you to configure AndroidManifest.xml, added:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
With Android Level> = 23 to read and write data on the in external storage device, you need to ask the user by using code. (See in the example).

2- Read and write files on the external storage example

Create a project named ExternalStorageDemo.
AndroidManifest.xml configuration allows read and write data on the external storage memory.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Full content of AndroidManifest.xml:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.o7planning.externalstoragedemo">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
 
The application interface:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true">

        <requestFocus />
    </EditText>

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="120dp"
        android:id="@+id/textView"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/editText"
        android:layout_above="@+id/button_save"
        android:layout_marginTop="10dp" />

    <Button
        android:id="@+id/button_save"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="save"
        android:layout_alignParentBottom="true"
        android:layout_alignLeft="@+id/textView"
        android:layout_alignStart="@+id/textView" />

    <Button
        android:id="@+id/button_read"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/button_save"
        android:layout_alignBottom="@+id/button_save"
        android:layout_toRightOf="@+id/button_save"
        android:text="read" />

    <Button
        style="?android:attr/buttonStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="List Dirs"
        android:id="@+id/button_list"
        android:layout_alignBottom="@+id/button_read"
        android:layout_toRightOf="@+id/button_read"
        android:layout_toEndOf="@+id/button_read" />

</RelativeLayout>
MainActivity.java
package org.o7planning.externalstoragedemo;

import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class MainActivity extends Activity {
   private EditText editText;
   private TextView textView;
   private Button saveButton;
   private Button readButton;
   private Button listButton;


   private static final int REQUEST_ID_READ_PERMISSION = 100;
   private static final int REQUEST_ID_WRITE_PERMISSION = 200;

   private final String fileName = "note.txt";

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

       editText = (EditText) findViewById(R.id.editText);
       textView = (TextView) findViewById(R.id.textView);

       saveButton = (Button) findViewById(R.id.button_save);
       readButton = (Button) findViewById(R.id.button_read);
       listButton = (Button) findViewById(R.id.button_list);

       saveButton.setOnClickListener(new OnClickListener() {

           @Override
           public void onClick(View arg0) {
               askPermissionAndWriteFile();
           }

       });


       readButton.setOnClickListener(new OnClickListener() {

           @Override
           public void onClick(View arg0) {
               askPermissionAndReadFile();
           }

       });

       listButton.setOnClickListener(new OnClickListener() {

           @Override
           public void onClick(View arg0) {
               listExternalStorages();
           }

       });
   }

   private void askPermissionAndWriteFile() {
       boolean canWrite = this.askPermission(REQUEST_ID_WRITE_PERMISSION,
               Manifest.permission.WRITE_EXTERNAL_STORAGE);
       //
       if (canWrite) {
           this.writeFile();
       }
   }

   private void askPermissionAndReadFile() {
       boolean canRead = this.askPermission(REQUEST_ID_READ_PERMISSION,
               Manifest.permission.READ_EXTERNAL_STORAGE);
       //
       if (canRead) {
           this.readFile();
       }
   }

   // With Android Level >= 23, you have to ask the user
   // for permission with device (For example read/write data on the device).
   private boolean askPermission(int requestId, String permissionName) {
       if (android.os.Build.VERSION.SDK_INT >= 23) {

           // Check if we have permission
           int permission = ActivityCompat.checkSelfPermission(this, permissionName);


           if (permission != PackageManager.PERMISSION_GRANTED) {
               // If don't have permission so prompt the user.
               this.requestPermissions(
                       new String[]{permissionName},
                       requestId
               );
               return false;
           }
       }
       return true;
   }


   // When you have the request results
   @Override
   public void onRequestPermissionsResult(int requestCode,
                                          String permissions[], int[] grantResults) {

       super.onRequestPermissionsResult(requestCode, permissions, grantResults);
       //
       // Note: If request is cancelled, the result arrays are empty.
       if (grantResults.length > 0) {
           switch (requestCode) {
               case REQUEST_ID_READ_PERMISSION: {
                   if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                       readFile();
                   }
               }
               case REQUEST_ID_WRITE_PERMISSION: {
                   if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                       writeFile();
                   }
               }
           }
       } else {
           Toast.makeText(getApplicationContext(), "Permission Cancelled!", Toast.LENGTH_SHORT).show();
       }
   }


   private void writeFile() {
  
       File extStore = Environment.getExternalStorageDirectory();
       // ==> /storage/emulated/0/note.txt
       String path = extStore.getAbsolutePath() + "/" + fileName;
       Log.i("ExternalStorageDemo", "Save to: " + path);

       String data = editText.getText().toString();

       try {
           File myFile = new File(path);
           myFile.createNewFile();
           FileOutputStream fOut = new FileOutputStream(myFile);
           OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
           myOutWriter.append(data);
           myOutWriter.close();
           fOut.close();

           Toast.makeText(getApplicationContext(), fileName + " saved", Toast.LENGTH_LONG).show();
       } catch (Exception e) {
           e.printStackTrace();
       }
   }

   private void readFile() {
  
       File extStore = Environment.getExternalStorageDirectory();
       // ==> /storage/emulated/0/note.txt
       String path = extStore.getAbsolutePath() + "/" + fileName;
       Log.i("ExternalStorageDemo", "Read file: " + path);

       String s = "";
       String fileContent = "";
       try {
           File myFile = new File(path);
           FileInputStream fIn = new FileInputStream(myFile);
           BufferedReader myReader = new BufferedReader(
                   new InputStreamReader(fIn));

           while ((s = myReader.readLine()) != null) {
               fileContent += s + "\n";
           }
           myReader.close();

           this.textView.setText(fileContent);
       } catch (IOException e) {
           e.printStackTrace();
       }
       Toast.makeText(getApplicationContext(), fileContent, Toast.LENGTH_LONG).show();
   }

   private void listExternalStorages() {
       StringBuilder sb = new StringBuilder();

       sb.append("Data Directory: ").append("\n - ")
               .append(Environment.getDataDirectory().toString()).append("\n");

       sb.append("Download Cache Directory: ").append("\n - ")
               .append(Environment.getDownloadCacheDirectory().toString()).append("\n");

       sb.append("External Storage State: ").append("\n - ")
               .append(Environment.getExternalStorageState().toString()).append("\n");

       sb.append("External Storage Directory: ").append("\n - ")
               .append(Environment.getExternalStorageDirectory().toString()).append("\n");

       sb.append("Is External Storage Emulated?: ").append("\n - ")
               .append(Environment.isExternalStorageEmulated()).append("\n");

       sb.append("Is External Storage Removable?: ").append("\n - ")
               .append(Environment.isExternalStorageRemovable()).append("\n");

       sb.append("External Storage Public Directory (Music): ").append("\n - ")
               .append(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).toString()).append("\n");

       sb.append("Download Cache Directory: ").append("\n - ")
               .append(Environment.getDownloadCacheDirectory().toString()).append("\n");

       sb.append("Root Directory: ").append("\n - ")
               .append(Environment.getRootDirectory().toString()).append("\n");

       Log.i("ExternalStorageDemo", sb.toString());
       this.textView.setText(sb.toString());
   }

}
Running app:
Use the " Android Device Manager" you can see the file is created.
See more about "Android Device Manager":