Saving Files In External Memory

By Kunal Kapoor
17-05-2018
1567

All Android devices have two file storage areas: "internal" and "external" storage. These names come from the early days of Android, when most devices offered built-in non-volatile memory (internal storage), plus a removable storage medium such as a micro SD card (external storage). Many devices now divide the permanent storage space into separate "internal" and "external" partitions. So even without a removable storage medium, these two storage spaces always exist, and the API behavior is the same regardless of whether the external storage is removable.




Because the external storage might be removable, there are some differences between these two options as follows.

External storage:

  • It's not always available, because the user can mount the external storage as USB storage and in some cases remove it from the device.
  • It's world-readable, so files saved here may be read outside of your control.
  • When the user uninstalls your app, the system removes your app's files from here only if you save them in the directory from 



The following example will help you to learn, how to store data/files in external memory

Overview:


Let's Create a simple layout with 2 Buttons, a Textview and an EditText

xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">


<TextView
android:id="@+id/textView"
android:layout_width="263dp"
android:layout_height="87dp"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.504"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.674" />

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="43dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="Show"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.88" />

<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="SAVE"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.328" />

<EditText
android:id="@+id/editText"
android:layout_width="289dp"
android:layout_height="59dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:ems="10"
android:inputType="textPersonName"
android:text="Name"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.503"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.066" />
android.support.constraint.ConstraintLayout
>


Next We'll add the permission for Read/Write in external storage in Android Manifest file

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


Lets start programming the JAVA code

First declare the Objects for all UI elements and other static parameters

private static final String DEBUG_TAG="EXTSTORAGE ";
private Button SaveButton,ReadButton;
private EditText editText;
private TextView textView;
public static final String FileName="MyFiles.txt";


Instantitate the variables in OnCreate method

editText=(EditText)findViewById(R.id.editText);
SaveButton=(Button)findViewById(R.id.button2);
ReadButton=(Button)findViewById(R.id.button);
textView=(TextView)findViewById(R.id.textView);


Declare the OnClick listeners for the Buttons and create separate methods for each function

SaveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ClickSaveButton(view);
}
});

ReadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ReadButtonPress(view);
}
});


Before we start coding the actual code, we'll have to require the permission to use the external storage in the device. Using external storage comes under Dangerous permissions as per Android documentation, thus you must also ask for permission from the user in RunTime.


Thus in Oncreate method itself, we'll have to check for permission for External memeory access, and if not, ask the user for it. 

First declare certain variables in MainActivity.class

private boolean hasPermission=false;
private static final int StoragePermissionID=34;


Next, paste the following code inside OnCreate method:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
hasPermission = true;
Log.d(DEBUG_TAG,"External Storage Allowed");
Toast.makeText(this,"Has permission",Toast.LENGTH_SHORT).show();
} else {
Log.d(DEBUG_TAG,"No Permission,Requesting now");
RequestSystemPermissions();
}
}else {
Toast.makeText(this,"Has permission",Toast.LENGTH_SHORT).show();
}


Next paste the following methods in MainActivity.class

private void RequestSystemPermissions(){
if (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {

// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.

} else {


ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
StoragePermissionID);


}
}
}

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

if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA)!=PackageManager.PERMISSION_GRANTED) {
switch (requestCode) {
case StoragePermissionID:
if (grantResults.length > 0) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {

// permission was granted, yay! Do the
// contacts-related task you need to do.
hasPermission = true;
Log.d(DEBUG_TAG,"PERMISSION GRANTED");
}
} else {

Toast.makeText(this, "Storage Permission denied", Toast.LENGTH_LONG).show();
hasPermission = false;
Log.d(DEBUG_TAG,"PERMISSION REJECTED");
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
}
}


Now based on this your app can make runtime request to user for External storage permission.

Next we will code the ClickSaveButton(View view) and ReadButtonPress(View view)method:


private void ReadButtonPress(View view) {
Log.d(DEBUG_TAG+"inside","ReadButtonPress");

if (hasPermission) {
File file = getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
File savefile = new File(file + File.separator + FileName);
Log.d(DEBUG_TAG + "ExtDire=", file.toString());
Log.d(DEBUG_TAG + "FileName=", FileName);
Log.d(DEBUG_TAG + "file=", savefile.toString());
String output = null;
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader(savefile));
StringBuilder stringBuilder = new StringBuilder();
String lin = "";
while ((lin = bufferedReader.readLine()) != null) {
stringBuilder.append(lin);
}

output = stringBuilder.toString();
bufferedReader.close();

textView.setText(output);
} catch (FileNotFoundException e) {
Log.d(DEBUG_TAG + "error1=", e.toString());
e.printStackTrace();
} catch (IOException e) {
Log.d(DEBUG_TAG + "error2=", e.toString());
e.printStackTrace();
}
}else {
RequestSystemPermissions();
}
}

@SuppressLint("LongLogTag")
private void ClickSaveButton(View view) {
Log.d(DEBUG_TAG + "inside", "ClickSaveButton");

if (hasPermission) {

String data = editText.getText().toString();
Log.d(DEBUG_TAG + "data ", data);

File file = getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
File savefile = new File(file + File.separator + FileName);
Log.d(DEBUG_TAG + "ExtDirectory=", file.toString());
Log.d(DEBUG_TAG + "FileName=", FileName);
Log.d(DEBUG_TAG + "file=", savefile.toString());

try {
FileOutputStream fileOutputStream = new FileOutputStream(savefile);
fileOutputStream.write(data.getBytes());
fileOutputStream.close();
} catch (FileNotFoundException e) {
Log.d(DEBUG_TAG + "error1=", e.toString());
e.printStackTrace();
} catch (IOException e) {
Log.d(DEBUG_TAG + "error2=", e.toString());
e.printStackTrace();
}
Toast.makeText(this, "Data Saved", Toast.LENGTH_SHORT).show();
}else {
RequestSystemPermissions();
}
}


Complete Java code: MainActivity.java

package com.ourcoaching.savedataexternalmemory;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.os.Build;
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.os.Bundle;
import android.util.Log;
import android.view.View;
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.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {

private static final String DEBUG_TAG="EXTSTORAGE ";
private Button SaveButton,ReadButton;
private EditText editText;
private TextView textView;
public static final String FileName="MyFile.txt";

private boolean hasPermission=false;
private static final int StoragePermissionID=34;

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

editText=(EditText)findViewById(R.id.editText);
SaveButton=(Button)findViewById(R.id.button2);
ReadButton=(Button)findViewById(R.id.button);
textView=(TextView)findViewById(R.id.textView);

SaveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ClickSaveButton(view);
}
});

ReadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ReadButtonPress(view);
}
});

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
hasPermission = true;
Log.d(DEBUG_TAG,"External Storage Allowed");
Toast.makeText(this,"Has permission",Toast.LENGTH_SHORT).show();
} else {
Log.d(DEBUG_TAG,"No Permission,Requesting now");
RequestSystemPermissions();
}
}else {
Toast.makeText(this,"Has permission",Toast.LENGTH_SHORT).show();
}

}


private void RequestSystemPermissions(){
if (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {

// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.

} else {


ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
StoragePermissionID);


}
}
}

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

if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA)!=PackageManager.PERMISSION_GRANTED) {
switch (requestCode) {
case StoragePermissionID:
if (grantResults.length > 0) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {

// permission was granted, yay! Do the
// contacts-related task you need to do.
hasPermission = true;
Log.d(DEBUG_TAG,"PERMISSION GRANTED");
}
} else {

Toast.makeText(this, "Storage Permission denied", Toast.LENGTH_LONG).show();
hasPermission = false;
Log.d(DEBUG_TAG,"PERMISSION REJECTED");
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
}
}

private void ReadButtonPress(View view) {
Log.d(DEBUG_TAG+"inside","ReadButtonPress");

if (hasPermission) {
File file = getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
File savefile = new File(file + File.separator + FileName);
Log.d(DEBUG_TAG + "ExtDire=", file.toString());
Log.d(DEBUG_TAG + "FileName=", FileName);
Log.d(DEBUG_TAG + "file=", savefile.toString());
String output = null;
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader(savefile));
StringBuilder stringBuilder = new StringBuilder();
String lin = "";
while ((lin = bufferedReader.readLine()) != null) {
stringBuilder.append(lin);
}

output = stringBuilder.toString();
bufferedReader.close();

textView.setText(output);
} catch (FileNotFoundException e) {
Log.d(DEBUG_TAG + "error1=", e.toString());
e.printStackTrace();
} catch (IOException e) {
Log.d(DEBUG_TAG + "error2=", e.toString());
e.printStackTrace();
}
}else {
RequestSystemPermissions();
}
}

@SuppressLint("LongLogTag")
private void ClickSaveButton(View view) {
Log.d(DEBUG_TAG + "inside", "ClickSaveButton");

if (hasPermission) {

String data = editText.getText().toString();
Log.d(DEBUG_TAG + "data ", data);

File file = getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
File savefile = new File(file + File.separator + FileName);
Log.d(DEBUG_TAG + "ExtDirectory=", file.toString());
Log.d(DEBUG_TAG + "FileName=", FileName);
Log.d(DEBUG_TAG + "file=", savefile.toString());

try {
FileOutputStream fileOutputStream = new FileOutputStream(savefile);
fileOutputStream.write(data.getBytes());
fileOutputStream.close();
} catch (FileNotFoundException e) {
Log.d(DEBUG_TAG + "error1=", e.toString());
e.printStackTrace();
} catch (IOException e) {
Log.d(DEBUG_TAG + "error2=", e.toString());
e.printStackTrace();
}
Toast.makeText(this, "Data Saved", Toast.LENGTH_SHORT).show();
}else {
RequestSystemPermissions();
}
}
}


Debug Log Tag data:

05-18 02:07:50.791 31696-31696/? D/EXTSTORAGE: No Permission,Requesting now
05-18 02:07:52.936 31696-31696/com.ourcoaching.savedataexternalmemory D/EXTSTORAGE: PERMISSION GRANTED
05-18 02:07:54.613 31696-31696/com.ourcoaching.savedataexternalmemory D/EXTSTORAGE inside: ClickSaveButton
05-18 02:07:54.613 31696-31696/com.ourcoaching.savedataexternalmemory D/EXTSTORAGE data: Name
05-18 02:07:54.617 31696-31696/com.ourcoaching.savedataexternalmemory D/EXTSTORAGE ExtDirectory=: /storage/emulated/0/Android/data/com.ourcoaching.savedataexternalmemory/files/Documents
05-18 02:07:54.617 31696-31696/com.ourcoaching.savedataexternalmemory D/EXTSTORAGE FileName=: MyFile.txt
05-18 02:07:54.617 31696-31696/com.ourcoaching.savedataexternalmemory D/EXTSTORAGE file=: /storage/emulated/0/Android/data/com.ourcoaching.savedataexternalmemory/files/Documents/MyFile.txt
05-18 02:07:56.018 31696-31696/com.ourcoaching.savedataexternalmemory D/EXTSTORAGE inside: ReadButtonPress
05-18 02:07:56.020 31696-31696/com.ourcoaching.savedataexternalmemory D/EXTSTORAGE ExtDire=: /storage/emulated/0/Android/data/com.ourcoaching.savedataexternalmemory/files/Documents
05-18 02:07:56.020 31696-31696/com.ourcoaching.savedataexternalmemory D/EXTSTORAGE FileName=: MyFile.txt
05-18 02:07:56.020 31696-31696/com.ourcoaching.savedataexternalmemory D/EXTSTORAGE file=: /storage/emulated/0/Android/data/com.ourcoaching.savedataexternalmemory/files/Documents/MyFile.txt


Download the code from GitHub



Related Tutorials