ファイル

資料

http://developer.android.com/guide/topics/resources/index.html

 

1.1 概説

FileIOはJavaの一般の機能です。JavaIOのおさらいを付録Aに記述しています。

Androidに特有なことは、InputStream/OutputStreamオブジェクトの取得のしかたです。通常のファイルの場合は、ファイル名から取得します。InputStream/OutputStreamオブジェクトをいったん取得すると、後は通常のJavaIOと同じです。

Android はリソースファイルを複数種類提供しています。Androidで扱うファイルの種類を表1-1に示します。

表1-1 ファイルの種類

#

区分

場所

特徴

1

リソース

res/rawディレクトリ下のファイル

リソースIDでInputStreamを取得する。

res/xml下のファイル

リソースIDでInputStreamを取得する

xmlパーサを使う。

assetsディレクトリ下のファイル*1

ファイル名でInputStreamを取得する。

2

リソース外

filesディレクトリ下のファイル

ファイル名でInputStream/OutputStreamを取得する。

SDカード

ファイル名でInputStream/OutputStreamを取得する。

注*1 assetsディレクトリはresディレクトリの下ではなく、resディレクトリと同じレベルに置かれます。

 

ファイルの種類によってInputStream/OutputStreamを取得する方法が異なっています。リソースファイルの種類ごとにInputStreamオブジェクトの取得方法を説明します。

 

1.2 res/raw下のファイル

Resources(android.content.res)オブジェクトのopenRawResource()メソッドを使います。また、Resourcesオブジェクトは通常、Context.getResources()メソッドで取得します。

コード例を次に示します。

// contextにContextオブジェクトが設定されている場合

Resources resources =  context.getResources();

InputStream inputStream = resources.openRawResource(R.raw.hello);

 

// Activity内では、次にように記述できます。

InputStream inputStream = getResources().openRawResource(R.raw.hello);

注 ファイルはraw直下になければなりません。

 

1.3xml下のファイル

ResourcesオブジェクトのgetXml()メソッドで、XmlResourceParserオブジェクトを取得します。XmlResourceParserは、標準のXmlPullParserを実装しています。その他に、AttributeSetインタフェースとclose()メソッドを実装しています。いったん、XmlResourceParserオブジェクトを取得すれば、通常の(Androidとは限らない)xmlをXmlPullParserで解析するのと同じ方法が使えます。

XmlPullParser の使い方については本資料では説明しません。XmlPullParserの使用例は、次の資料に記述されています。

資料

http://www.ibm.com/developerworks/opensource/library/x-android/index.html(英語)

http://www.ibm.com/developerworks/jp/xml/library/x-android/(日本語)

Android で XML を扱う,モバイル機器用の Java アプリケーションを作成する

 

この資料が扱っている資料は、xml下のxmlではありませんが、XmlPullParserの使い方は同じです。

 

1.4assets下のファイル

AssetManager(android.content.res)オブジェクトのopen()メソッドをを使います。AssetManagerオブジェクトはContext.getAssets()メソッドで取得できます。

コード例を次に示します。

// contextにContextオブジェクトが設定されている場合

AssetManager assetManager = context.getAssets();

InputStream inputStream = assetManager.open("file name");

 

// Activity内では、次にように記述できます。

InputStream inputStream = getAssets ().open("file name");

注file nameは、拡張子があれば拡張子も含みます。assetsの直下である必要はありません。

 

open()メソッドは、第2引数でアクセスモードを設定する版もあります。

AssetManagerはファイルを扱うためのメソッドをいくつか持っています。このうち、list()メソッドを紹介します。

 

list()メソッド

public final String[] list (String path)

引数

#

引数

説明

1

path

assets下の相対的パス。例docs/home.html

 

戻り値String型の配列。与えられたパスにある全ファイル(asset)のリスト。ファイル名は、与えられたパスに相対的です。

 

コード例を次に示します。

String[] list = assetManager.list ("diamond");

 

1.5files下のファイル

アプリの中で作成し、読むファイルです。"private file"と呼んでいます。他のアプリに公開するフラグはありますが、他ののアプリから参照する方法は記述されていません。

InputStreamオブジェクトとOutputStreamオブジェクトはそれぞれContextのopenFileInput()メソッドとopenFileOutput()メソッドを使って取得します。ファイルを削除するメソッドdeleteFile()メソッドもあります。

各メソッドの第1引数はファイル名です。

openFileOutput()メソッドは第2引数でモードを指定できます。アクセスをアプリ内に限るか否かを指定できます。また同じ引数で新規に作るか、既存のファイルの最後から続けて書くか指定できます。

openFileInput()メソッドとopenFileOutput()の戻り値の型はそれぞれ、FileInputStreamとFileOutputStreamです。これはそれぞれ、InputStreamとOutputStreamを実装した型ですので、InputStream又はOutputStream型が必要な場合は、そのまま使えます。ファイルを扱う場合は、FileInputStreamとFileOutputStream型で受けると便利です。

deleteFile()メソッドの戻り値はbooleanです。削除できたときはtrue、削除できなかったときはfalseを戻します。

ファイルの実体は次の場所に作成されます。これはDDMSのファイルのエクスプローラで確認できます。

data/data/<アプリ パッケージ>/files/<ファイル名>

 

コード例

FileOutputStream outputStream = openFileOutput("some.txt", Context.MODE_PRIVATE);

FileInputStream  inputStream  = openFileInput("some.txt");

boolean rtn = deleteFile("some.txt");

 

1.6 SDカード

AVDでSDカードを模擬する方法は付録 Bを参照して下さい。

SDカードは、通常のPCのハードディスクの役割をします。単にファイルIOだけでなく、ディレクトリの作成・削除等もできなければなりません。そのためにAndroidは、ファイルの実体に対応するFileクラス(java.io)を取得するメソッドを提供しています。FileクラスはAndroid特有のクラスではありません。Javaの標準ライブラリに含まれるクラスです。Fileクラスは、ファイルやディレクトリの作成・削減・名前の変更等、入出力ではなく、ファイルの実体を操作するメソッドを持っています。Fileオブジェクトを引数にして、ファイルIOのオブジェクトを生成できます。

SDカードに対応するFileオブジェクトは、Environment(android.os)オブジェクトのgetExternalStorageDirectory()メソッドを使って取得します。

ユーザ(ケイタイの利用者)が外部記憶装置を挿入していたとしても、そのディレクトリにアクセスできないこともあります。また、外部記憶装置を挿入していなかったとか、他の何らかの問題が起きて、そのディレクトリにアクセスできないこともあります。アプリはEnvironment.getExternalStorageState()メソッドを使って、そのときの状態を知ることができます。

アプリは最上位のディレクトリは使うのべきではありません。というのは、ユーザの名前空間のルートを他の名前と混じらないようにすべきだからです。アプリ内だけで利用するファイルはすべてContext.getExternalFilesDir()メソッドで取得できるディレクトリに置くべきです。そこに置いておくと、該当するアプリがアンインストールされると、Androidが自動的にそのファイルを削除します。アプリ間で共用するファイルはEnvironment.getExternalStoragePublicDirectory(String)メソッドで取得できるディレクトリに置くべきです。

外部記憶装置の状態をモニターするコードの例が次の資料(マニュアル)に記載されていますので参照して下さい。

http://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory()

 

次は、

        File topDir = Environment.getExternalStorageDirectory();

        String strDir1Path = topDir.getAbsolutePath();

        File dir1 = new File(strDir1Path);

        dir1.mkdir();

        String strFile1 = dir1.getAbsolutePath() + "/file1.txt";

        File file1 = new File(strFile1);

        file1.createNewFile(); // IOException

        FileOutputStream fos = new FileOutputStream(file1);// FileNotFoundException

        fos.write("Hello, World!".getBytes());//IOException

注 例外の処理は省略しています。実用のIOのコードとして推奨できる内容ではありません。SDカードの扱い方を示す目的のコードです。

 

SDカードに書き込む場合は、そのためのパーミッションが必要です。次のパーミッションをAndroidManifest.xmlに追加しなければなりません。

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

 

 

2.例

例題のソースコードは付録に掲載します。また、web上の参考になるサイトも付録で紹介しています。

 

2.1 ヘルパーメソッド

ファイルの種類に関係なく使うヘルパーメソッドをまず作成します。

 

2.1.1 readTextFile

引数でInputStreamを与えて、そこからテキストファイルを読み、ログにプリントするメソッドです。テキストはBufferedReaderオブジェクトを使って読みます。

仕様

private void readTextFile(InputStream is,String title)

 

titleはデバッグ用の情報を書くときに、タイトルとして使う文字列です。

これはJavaのjdkの環境でテストできます。

 

2.1.2 writeTextFile

引数でOutputStreamを与えて、そこへテキストファイルを書きます。内容は固定します。

仕様

private void writeTextFile(OutputStream os,String title, String prefix)

 

prefixは各行の先頭に追加する文字列です。

これはJavaのjdkの環境でテストできます。

 

2.1.2 parseXml()

これは、一度しか使いません。理解しやすくする目的で一つのメソッドにまとめます。

 

2.2 ファイルの入出力

この例で使うファイルはテキストファイルです。コードはUTF-8にします。

注DDMSのログは"漢字"を表示できないようです(設定の問題かもしれません)。漢字を含む場合は、TextView等で表示して確認して下さい。掲載したコードは、ファイルの内容をログに出力していますので漢字が化けます。

 

2.2.1res/rawのファイル

res/rawの下にraw_test.txtのファイルを作ります。このファイルを読むためのコードは次の通りです。

// raw

InputStream rawIs = getResources().openRawResource(R.raw.raw_test);

readTextFile(rawIs,"raw resource");

 

2.2.2xmlファイル

res/xmlの下にstations.xmlファイルを作成します。xmlの解析は、xmlの形式に依存します。この例で使ったxmlファイルの一部を次に示します。

<?xml version="1.0" encoding="utf-8"?>

<stations>

    <station>Tokyo</station>

    <station>Shinagawa</station>

    ...

</stations>

 

このファイルを解析するためのXmlPullParserオブジェクトを取得するコードは次の通りです。

// xml

XmlPullParser xpp = getResources().getXml(R.xml.stations);

 

2.2.3assets下のファイル

assetsディレクトリの下にディレクトリsubdir_assetsを作ります。subdir_assetsの下にasset_test.txtファイルを作ります。このファイルを読むためのコードは次の通りです。

//assets

try{

    InputStream assetIs = getAssets().open("subdir_assets/asset_test.txt");

    readTextFile(assetIs,"asset file");

}catch(IOException e){

    Log.e(tag,"assetsIs IOException msg=" + e.getMessage());

}

 

リソースIdを使う場合と違って、assets下のファイルをオープンするときは、例外が生じる恐れがあります。try・catch構文等でこれを捕える処理が必要です。

 

2.2.4files下のファイル

ファイルの生成もプログラム内で行わなければなりません。ファイル名はfiles_test.txtにします。次のコードは、前半のtry-catchがこのファイルへの出力、後半のtry-catchがこのファイルからの入力の処理をしています。

//files

String filesFileName = "files_test.txt";

try{

    FileOutputStream filesOs = openFileOutput(filesFileName, Context.MODE_PRIVATE);

    writeTextFile(filesOs,"files output file","files");

}catch(FileNotFoundException e){

    Log.e(tag,"FileNotFoundException msg=" + e.getMessage());

}

try{

    InputStream  filesIs  = openFileInput(filesFileName);

    readTextFile(filesIs,"files input file");

}catch(FileNotFoundException e){

    Log.e(tag,"FileNotFoundException msg=" + e.getMessage());

}

 

実行後、data/data/<アプリ パッケージ>/filesの下にfiles_test.txtができていることを確認して下さい。

 

2.2.5 SDカード

SDカードをマウントする方法は付録を参照して下さい。

SDカードの最上位のディレクトリの下にディレクトリdir1を作り、その下にfile1.txtを作ります。これにデータを書き込み、いったんクローズした後、このファイルを読みます。このコードを次に示します。

Fileクラスを使っている点がこれまでと異なります。FileIOのオブジェクトは、Fileオブジェクトを引数に取るコンストラクタを使って生成しています。もちろん、Fileオブジェクトの代わりに、ファイル名を使ってもできます。

 

// SDカード

// 最上位のディレクトリを取得

File topDir = Environment.getExternalStorageDirectory();

// 一つしたのディレクトリを作る。

String strDir1Path = topDir.getAbsolutePath() + "/dir1";

File dir1 = new File(strDir1Path);

dir1.mkdir();

// ファイルの作成

String strFile1 = dir1.getAbsolutePath() + "/file1.txt";

File file1 = new File(strFile1);

FileOutputStream sdOs = null;

try{

    file1.createNewFile(); // IOException

}catch(IOException e){

    Log.e(tag,"IOException msg=" + e.getMessage());

}

// ファイルへの出力

try{

    sdOs = new FileOutputStream(file1);// FileNotFoundException

}catch(FileNotFoundException e){

    Log.e(tag,"FileNotFoundException msg=" + e.getMessage());

}

writeTextFile(sdOs,"SD output file","SD");

// ファイルからの入力

try{

    InputStream  sdIs  = new FileInputStream(file1);

    readTextFile(sdIs,"SD input file");

}catch(FileNotFoundException e){

    Log.e(tag,"FileNotFoundException msg=" + e.getMessage());

}

 

実行するためには次のパーミッションをAndroidManifest.xmlに追加しなければなりません。

 

付録

付録 Java IOのおさらい

Javaの入出力の基本のクラスはInputStreamクラスとOutputStreamクラスです。

入力を担当するInputStreamに限定して説明します。

InputStreamクラスがどれくらい基本のクラスかといえば、もしInputStreamクラスのインスタンスがなんらかの方法で取得できたとしたら、JavaのIOの機能がすべて利用できるといえます。

InputStreamクラスは抽象クラスです。ですから、正確に言えば、InputStreamクラスのインスタンスを取得するということは、InputStreamを継承した具体クラスのインスタンスを得るという意味です。

 

ファイルの場合を例あげましょう。

 

1:InputStream is = new FileInputStream("test");

2:BufferedInputStream bis = new BufferedInputStream(is);

3:DataInputStream dis = new DataInputStream(is);

4:InputStreamReader isr = new InputStreamReader(is)

5:BufferedReader br = new BufferedReader(isr)  *1

 

ここに挙げたクラスは、どれもJavaIOの重要なクラスです。

ここで大切なことは、第1行目でいったんInputStreamオブジェクトを取得すると、後のインスタンシェートにはファイル名が不要だということです。

仮に、第1行目の代わりに、何らかの方法でInputStreamオブジェクトを取得できると、2行目以降は、そのまま使えるということです。

逆に言えば、ファイルに限らず、InputStreamオブジェクトを提供できるモノ(オブジェクト)があれば、JavaIOのクラスが活用できるということです。

開発者の立場から言えば、InputStreamオブジェクトを提供するオブジェクトがある場合、それをどのように取得するか分かれば、その後はJavaIOの知識がそのまま生かせるということです。

 

注*1 通常、ファイル名が分かっている場合は次の方法を使います。

BufferedReader br = new BufferedReader(new FileReader("test")

br = new BufferedReader(isr)の方法はファイル名が分かっていなくても使える方法です。使用頻度が高いファイル名が分かっている場合については、簡略にできるようにFileReaderクラスが低級されていると考えられます。

 

付録 SDカードの模擬

AVDを作る際、SDカード作成の指定をした場合、そのAVDを使うと自動でSDカードがマウント(挿入)されるはずです。

次の説明はAVDを作る際、SDカード作成の指定をしなかった場合です。SDカードを使うテストが多くはない場合、この方法が適しています。

 

B.1SDカードイメージの作成

資料 http://developer.android.com/guide/developing/tools/othertools.html

mksdcard [-l label] <size>[K|M] <file>

例 >mksdcard -l sdcard1 10M C:\android\sdcard.iso

 

sizeで指定した値だけ割り当てられます。割り当ての時間がかかり、かつファイルもそれだけ消費します。そのため、sizeは必要最小限に設定すべきです。ただし、9M以上でなければなりません。実際には10M以上ないとエラーが出るようです。ただし、環境に依存するかもしれません。

 

B.2SDカードイメージ付きでemulatorを起動

B.2.1 コマンドプロセッサーから起動する場合

emulator -avd AVD名 -sdcard  full_file_name

例>emulator -avd the2nd_AVD -sdcard C:\android\sdcard.iso

 

B.2.2eclipse場合

実行の構成で、実行時のパラメータを設定します。

Run >> Run Configurations >> targetタブ

 >> 下の部分 Additional Emulator Command Line Optionsの入力領域に

-sdcard  full_file_nameを設定します。

 

B.3 パーミッションの追加

SDカードに書き込む場合は次のパーミッションが必要です。

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

 

付録   参考webサイト

raw フォルダ

http://android-er.blogspot.com/2010/07/display-text-file-in-resraw_01.html

Beginner to beginner

Thursday, July 1, 2010

Display text file in /res/raw

 

xml

http://thedevelopersinfo.com/2009/12/14/using-xml-file-resources-in-android/

The Developer's Info

Using XML file resources in Android

By Oleg Mazurashu, on December 14th, 2009

 

assets

http://thedevelopersinfo.com/2009/11/17/using-assets-in-android/

The Developer's Info

Using assets in Android

By Oleg Mazurashu, on November 17th, 2009

 

files

http://thedevelopersinfo.com/2009/11/26/using-filesystem-in-android/

The Developer's Info

Using filesystem in Android

By Oleg Mazurashu, on November 26th, 2009

 

SDカード

http://thedevelopersinfo.com/2010/01/13/working-with-sdcards-filesystem-in-android/

The Developer's Info

Working with SDCards filesystem in Android

By Oleg Mazurashu, on January 13th, 2010

 

http://thedevelopersinfo.com/2009/10/17/putting-files-on-sdcard-in-android/

Putting files on SDCard in Android

コマンドでSDカードにファイルをコピーする方法が記述されています。

 

http://thedevelopersinfo.com/2009/10/13/creating-sdcard-for-android-emulator/

Creating SDCard for Android emulator

本資料でも紹介したemulator用のSDカードの作り方を説明しています。

 

http://thedevelopersinfo.com/2009/10/13/emulating-sdcard-in-android-emulator/

Emulating SDCard in Android emulator

SDをマウントしたAVDをコマンドから起動する方法を説明しています。

 

付録D 例題のソースコード

Activity

public class HelloRes_0_1 extends Activity {

    private String tag = this.getClass().getSimpleName();

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        Log.d(tag,"onCreate starts.");

       

        // raw

        InputStream rawIs = getResources().openRawResource(R.raw.raw_test);

        Log.d(tag,"onCreate calling readTextFile.");

        readTextFile(rawIs,"raw resource");

       

        // xml

        parseXml();

       

        //assets

        try{

            InputStream assetIs = getAssets().open("subdir_assets/asset_test.txt");

            readTextFile(assetIs,"asset file");

        }catch(IOException e){

            Log.e(tag,"assetsIs IOException msg=" + e.getMessage());

        }

       

        //files

        String filesFileName = "files_test.txt";

        try{

            FileOutputStream filesOs = openFileOutput(filesFileName, Context.MODE_PRIVATE);

            writeTextFile(filesOs,"files output file","files");

        }catch(FileNotFoundException e){

            Log.e(tag,"FileNotFoundException msg=" + e.getMessage());

        }

        try{

            InputStream  filesIs  = openFileInput(filesFileName);

            readTextFile(filesIs,"files input file");

        }catch(FileNotFoundException e){

            Log.e(tag,"FileNotFoundException msg=" + e.getMessage());

        }

       

        // SDカード

        // 最上位のディレクトリを取得

        File topDir = Environment.getExternalStorageDirectory();

        // 一つしたのディレクトリを作る。

        String strDir1Path = topDir.getAbsolutePath() + "/dir1";

        File dir1 = new File(strDir1Path);

        dir1.mkdir();

        // ファイルの作成

        String strFile1 = dir1.getAbsolutePath() + "/file1.txt";

        File file1 = new File(strFile1);

        FileOutputStream sdOs = null;

        try{

            file1.createNewFile(); // IOException

        }catch(IOException e){

            Log.e(tag,"IOException msg=" + e.getMessage());

        }

        // ファイルへの出力

        try{

            sdOs = new FileOutputStream(file1);// FileNotFoundException

        }catch(FileNotFoundException e){

            Log.e(tag,"FileNotFoundException msg=" + e.getMessage());

        }

        writeTextFile(sdOs,"SD output file","SD");

        // ファイルからの入力

        try{

            InputStream  sdIs  = new FileInputStream(file1);

            readTextFile(sdIs,"SD input file");

        }catch(FileNotFoundException e){

            Log.e(tag,"FileNotFoundException msg=" + e.getMessage());

        }

    }

   

   

    private void readTextFile(InputStream is,String title){

        Log.d(tag,"*** readTextFile: " + title + " ***");

        try{       

            Reader reader = new InputStreamReader(is,"UTF-8"); // UnsupportedEncodingException

            BufferedReader br = new BufferedReader(reader);

            String line;

            int k=0;

            while((line=br.readLine())!=null){  // IOException

                k++;

                Log.d(tag,k + ":" + line);

            }

        }catch(UnsupportedEncodingException e){

            Log.e(tag,"UnsupportedEncodingException msg=" + e.getMessage());

        }catch(IOException e){

            Log.e(tag,"IOException msg=" + e.getMessage());

        }finally{

            if(is!=null){

                try{

                    is.close();

                }catch(Exception e){

                }

            }

        }

    }

   

    private void writeTextFile(OutputStream os,String title, String prefix){

        Log.d(tag,"*** writeTextFile: " + title + " ***");

        String[] lines ={

             "file test 1"

            ,"file test 2 漢字 かな カナ"

            ,"file test 3 end"

        };

        BufferedWriter bw=null;

        try{       

            Writer writer = new OutputStreamWriter(os); // UnsupportedEncodingException

            bw = new BufferedWriter(writer);

            Log.d(tag,"writeTextFile number of written lines=" + lines.length);

            int i;

            for(i=0;i<lines.length;i++){

                bw.write(prefix + " " + lines[i]);  // IOException

                bw.newLine();

            }

        }catch(UnsupportedEncodingException e){

            Log.e(tag,"UnsupportedEncodingException msg=" + e.getMessage());

        }catch(IOException e){

            Log.e(tag,"IOException msg=" + e.getMessage());

        }finally{

            if(bw!=null){

                try{

                    bw.close();

                }catch(Exception e){

                }

            }

        }

    }

   

    private void parseXml(){

        XmlPullParser xpp = getResources().getXml(R.xml.stations);

        int t;

        boolean dataF=false;

        String station;

        try{

            while((t=xpp.getEventType())!=XmlPullParser.END_DOCUMENT){

                if(t==XmlPullParser.START_TAG){

                    if(xpp.getName().equals("station")){

                        dataF=true;

                    }else{

                        dataF=false;

                    }

                }else{

                    if(dataF && t==XmlPullParser.TEXT){

                        station = xpp.getText();

                        Log.d(tag,"station=" + station);

                    }

                    dataF=false;

                }

                xpp.next();

            }

        }catch(XmlPullParserException e){

            Log.e(tag,"ERROR during parsing, msg=" + e.getMessage());

        }catch(IOException e){

            Log.e(tag,"ERROR during parsing, msg=" + e.getMessage());

        }

    }

}

 

raw_test.txt

raw file test 1

raw file test 2 漢字 かな カナ

raw file test 3 end

 

stations.xml

<?xml version="1.0" encoding="utf-8"?>

<stations>

    <station>Tokyo</station>

    <station>Shinagawa</station>

    <station>ShinYokohama</station>

    <station>Odawara</station>

    <station>Atami</station>

    <station>Mishima</station>

    <station>ShinFuji</station>

    <station>Shizuoka</station>

    <station>Kakegawa</station>

    <station>Hamamatsu</station>

    <station>Toyohashi</station>

    <station>MikawaAnjyo</station>

    <station>Nagoya</station>

    <station>GifuHashiba</station>

    <station>Maebara</station>

    <station>Kyouto</station>

    <station>ShinOsaka</station>

</stations>

 

asset_test.txt

asset file test 1

asset file test 2 漢字 かな カナ

asset file test 3 end

 

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest ... >

    <application ... >

      ...

    </application>

    <uses-permission

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

</manifest>

 

以上