Tuesday, March 5, 2013

File Writing in Android

Android programming is Java "in mufti". The following is an example  which will be added to as time goes on. The work was performed on a Kindle, using AIDE. The text are largely plagiarized from public sources on the internet, here being brought into small, bite (hah) sized portions.

This example illustrates writing text to a file. Notice that I made a mistake in naming the file, as "MainActivity" is meaningless when it shows up as a choice in the Apps screen. It seems to me very confusing at the beginning to choose names before it is clear where those names will be used.

package com.wpd0101.filewritetest;

import android.app.*;
import android.os.*;
import android.util.*;
import android.widget.*;
import java.io.*;

public class MainActivity extends Activity
{
private static final String LOG_TAG = "FileWriteTestDebug";
    /** Called when the activity is first created. */
    Toast toast;
@Override
    public void onCreate(Bundle savedInstanceState)
{
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
String filename = "wpd_test_file.txt";
String data_string = "Written by filewritetest into newly created (or not) directory";

if (isExternalStorageWritable())
{
toast = Toast.makeText(getApplicationContext(), "yes external storage is writeable", Toast.LENGTH_LONG);
toast.show();
// }

TextView textView = new TextView(this);
textView.setTextSize(40);

String pathToExternalStorage = Environment.getExternalStorageDirectory().toString();
File appDirectory = new File(pathToExternalStorage + "/newDirectory");

// have the object build the directory structure, if needed.
appDirectory.mkdirs();

filename = "./newDirectory/" + filename;
textView.setText(filename);
setContentView(textView);

File file = new File(Environment.getExternalStorageDirectory(), filename);
FileOutputStream fos;
byte[] data = data_string.getBytes();
try
{
fos = new FileOutputStream(file);
fos.write(data);
fos.flush();
fos.close();
toast = Toast.makeText(getApplicationContext(), "file written as desired", Toast.LENGTH_SHORT);
toast.show();
}
catch (FileNotFoundException e)
{
// handle exception
toast = Toast.makeText(getApplicationContext(), "FilrNotFoundException", Toast.LENGTH_LONG);
toast.show();
}
catch (IOException e)
{
// handle exception
// toast = Toast.makeText(getApplicationContext(), "IOException", Toast.LENGTH_LONG);
// toast.show();
myToast("IOException");
}
}
}
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable()
{
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state))
{
return true;
}
return false;
}
public void myToast(String toast_msg)
{
toast = Toast.makeText(getApplicationContext(), toast_msg, Toast.LENGTH_LONG);
toast.show();
}
}



This code starts with a global declaration for a "Toast", which is a way of communicating while debugging to see what's going on. AIDE does not have debugging facilities, so one is reduced to writing debugging information on the screen as the program chugs along in this (and other) manners. This one (Toast) is easy to use.
The LOG_TAG is defined so that we can label outputs which use the "Log.e()" function. We didn't use it in this example.

PLEASE REMEMBER TO INCLUDE THE APPROPRIATE STATEMENT IN THE ANDROID MANIFEST TO ALLOW WRITING TO THE sdcard. Without this permission, writing is impossible. This is a protective feature.

Upon starting, we need to create definitions which will be used further on in the code. The first two lines are created by AIDE, and of course the rest is discretionary.


  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
String filename = "wpd_test_file.txt";
String data_string = "Written by filewritetest into newly created (or not) directory";

The "data_string" is text which will be written into the newly created file.

The following code tests to see if the sdcard is writeable:

if (isExternalStorageWritable())
{
toast = Toast.makeText(getApplicationContext(), "yes external storage is writeable", Toast.LENGTH_LONG);
toast.show();
// }
and writing this code and running it, you see that it is, indeed writeable. Toast is a method of outputing intermediate information without goofing up the layout of the output screen.

The following creates a region of the screen for outputting text, and then creates a new directory connected to the current directory, whatever it is, as a sub-directory:

TextView textView = new TextView(this);
textView.setTextSize(40);

String pathToExternalStorage = Environment.getExternalStorageDirectory().toString();
File appDirectory = new File(pathToExternalStorage + "/newDirectory");

// have the object build the directory structure, if needed.
appDirectory.mkdirs();

filename = "./newDirectory/" + filename;
textView.setText(filename);
setContentView(textView);
"pathToExternbalStorage" establishes where we are on the sdcard, and the next two lines create the subdirectory. Finally, we concatenate the current path with the new directory name with the to-be-created file name and check that we've got it right by writing it to the textView.

Finally, we write the data to the new file:

File file = new File(Environment.getExternalStorageDirectory(), filename);
FileOutputStream fos;
byte[] data = data_string.getBytes();
try
{
fos = new FileOutputStream(file);
fos.write(data);
fos.flush();
fos.close();
toast = Toast.makeText(getApplicationContext(), "file written as desired", Toast.LENGTH_SHORT);
toast.show();
}
catch (FileNotFoundException e)
{
// handle exception
toast = Toast.makeText(getApplicationContext(), "FilrNotFoundException", Toast.LENGTH_LONG);
toast.show();
}
catch (IOException e)
{
// handle exception
// toast = Toast.makeText(getApplicationContext(), "IOException", Toast.LENGTH_LONG);
// toast.show();
myToast("IOException");
}
Toasting as we go if there are errors or successes. rather than use the same code, we create a subroutine, myToast, to Toast for us:
public void myToast(String toast_msg)
{
toast = Toast.makeText(getApplicationContext(), toast_msg, Toast.LENGTH_LONG);
toast.show();
}
Note that this internal subroutine (old fashioned language, sorry) gets its toast content from the caller. It reduces toasting to a 1-line invocation.


March 5, 2013