ファイル入出力Ⅰ
JV⑨ □ ファイル入出力(概要、手順) □ ファイル入出力(使用クラス、使用コンストラクタ) □ ファイル入出力(文字コード処理) □ ファイル入出力(ファイル情報の取得) □ ファイル入出力(バイナリファイルの入出力処理) 今回の課題項目 □ ファイル入出力の基本(概要、手順、使用クラス) □ ファイル入出力の実践(ファイル情報の取得、バイナリファイルの操作) 今回の重点項目■ ファイル入出力の概要 ■ プログラムを作成する際、『或るファイルのデータを読み込み、別のファイルへ書き出す』、『或るデー タを読み込む際、データのフィルタ処理を行う』、『或るデータの書き込みを、別のプログラムの入力値 とする』等と謂う入出力に関する処理を行う事が有る。Java では、其等の処理を java.io パッケージに 含まれる様々なクラスで対応して居る。 ■ ファイル入出力の手順
ファイル入出力(File Input & Output)とは、ファイルの内容を読み出したり(Input:入力)、ファ イルに情報を書き込んだり(Output:出力)する事で有る。ファイル入出力を行う為には、ファイルに 格納されたデータを変数に読み込んだり、変数(又は、定数)の内容をファイルに書き込む事に成る。 ファイル入出力の処理は、概ね、以下の手順で行われる。 ① ファイルを開く(ソースに対し読み込み、又は、書き込みストリームを開く) ② データの読み込み、又は、書き込みを行う ③ ファイルを閉じる(ソースに対し読み込み、又は、書き込みストリームを閉じる) 猶、Java では、総ての入出力はストリーム(Stream:情報の流れ)と看做される。即ち、キーボード からの入力も、ディスプレイへの出力も、デバイスからの入出力も、ネットワークとの入出力も、総て ストリームと謂う概念で考えられる。此の為、ファイル、ネットワーク、デバイス等の入出力を、同じ 概念で扱う事が出来る。 ■ 入出力処理のクラス 入出力関係のクラスは、大別すると、文字ストリーム用のクラスとバイトストリーム用のクラスの2種 に成る。文字ストリーム用のクラスはテキストデータ等の 16 ビット文字の入出力に使用され、バイト ストリーム用のクラスは画像・圧縮データ等のバイナリデータの入出力に使用される。ファイル入出力 では、java.io パッケージが提供する以下のクラスを使用する(要 import java.io.*)。
文字ストリーム java.io.FileReader クラス テキストファイルから文字を読み出す java.io.FileWriter クラス テキストファイルに文字や文字列を書き込む バイトストリーム java.io.FileInputStream クラス バイナリファイルからデータを読み出す java.io.FileOutputStream クラス バイナリファイルにデータを書き込む java.io.InputStreamReader クラス バイトデータを読み込んで文字に変換する java.io.OutputStreamWriter クラス 書き込まれた文字をバイトデータに符号化する 猶、WEB ブラウザ上で動作するアプレットに付いては、セキュリティの観点から、ファイルへの入出 力は許可されて居ない。
フ
フ
ァ
ァ
イ
イ
ル
ル
入
入
出
出
力
力
■ コンストラクタ ファイル入出力処理で使用されるクラスの主なコンストラクタを下記に示す。 FileReader クラス コンストラクタ 説明 FileReader(File) 引数に読み込むファイルのFile オブジェクトを指定する。 FileReader(FileDescriptor) 引数にFileDescriptor オブジェクトを指定する。 FileReader(String) 引数に読み込むファイルのパス名を指定する。 例:ファイルパス名を指定してFileReader オブジェクト abc を生成
FileReader abc = new FileReader("abc.txt");
例:FileDescriptor オブジェクトを指定して FileReader オブジェクト def を生成 FileReader def = new FileReader(FileDescriptor.in);
FileWriter クラス
コンストラクタ 説明
FileWriter(File) 引数に書き込むファイルのFile オブジェクトを指定する。 FileWriter(File, boolean) 引数に書き込むファイルのFile オブジェクトを指定する。第 2
引数がtrue の場合は、ファイルの最後からデータを書き込む。 FileWriter(FileDescriptor) 引数にFileDescriptor オブジェクトを指定する。
FileWriter(String) 引数に書き込むファイルのパス名を指定する。
FileWriter(String, boolean) 引数に書き込むファイルのパス名を指定する。第2 引数が true の場合は、ファイルの最後からデータを書き込む(Append)。 例:xyz.txt ファイルの最後から書き込み処理を行うオブジェクト xyz を生成
boolean append = true;
FileWriter xyz = new FileWriter("xyz.txt", append);
FileInputStream クラス
コンストラクタ 説明
FileInputStream(File) 引数に読み込むファイルのFile オブジェクトを指定する。 FileInputStream(FileDescriptor) 引数にFileDescriptor オブジェクトを指定する。
FileInputStream(String) 引数に読み込むファイルのパス名を指定する。
例:File オブジェクト生成後、File オブジェクトを指定して FileInputStream オブジェクト aaa を生成 File tmpFile = new File("AAA.gif");
FileInputStream aaa = new FileInputStream(tmpFile);
FileOutputStream クラス
コンストラクタ 説明
FileOutputStream(File) 引数に書き込むファイルのFile オブジェクトを指定する。 FileOutputStream(File, boolean) 引数に書き込むファイルのFile オブジェクトを指定する。第 2
引数がtrue の場合は、ファイルの最後からデータを書き込む。 FileOutputStream(FileDescriptor) 引数にFileDescriptor オブジェクトを指定する。
FileOutputStream(String) 引数に書き込むファイルのパス名を指定する。
FileOutputStream(String, boolean) 引数に書き込むファイルのパス名を指定する。第2 引数が true の場合は、ファイルの最後からデータを書き込む(Append)。
InputStreamReader クラス コンストラクタ 説明 InputStreamReader (InputStream) 第1 引数に読み込む InputStream クラスのオブジェクトを指定する。此の場 合はデフォルトのエンコード方式が使われる。 InputStreamReader (InputStream, String) 第1 引数に読み込む InputStream クラスのオブジェクトを、第 2 引数にエン コード方式を指定する。エンコード方式の指定はIANA Charset Registry に 記載される文字列を使用する。
例:FileInputStream オブジェクト生成後、FileInputStream オブジェクトとエンコード方式を引数に指 定してInputStreamReader オブジェクト abc を生成
FileInputStream abcFile = new FileInputStream("abc.txt");
InputStreamReader abc = new InputStreamReader(abcFile, "EUC-JP");
OutputStreamWriter クラス コンストラクタ 説明 OutputStreamWriter (OutputStream) 第1 引数に書き込む OutputStream クラスのオブジェクトを指定する。此の 場合はデフォルトのエンコード方式が使われる。 OutputStreamWriter (OutputStream , String) 第1 引数に書き込む OutputStream クラスのオブジェクトを、第 2 引数にエ ンコード方式を指定する。エンコード方式の指定はIANA Charset Registry に記載される文字列を使用する。
例:FileOutputStream オブジェクト生成後、FileOutputStream オブジェクトとエンコード方式を引数に 指定してOutputStreamWriter オブジェクト xyz を生成
FileOutputStream xyzFile = new FileOutputStream("xyz.txt");
OutputStreamWriter xyz = new OutputStreamWriter(xyzFile, "EUC-JP");
■ 文字コード処理 日本語の処理を複雑にして居る理由の一つに、エンコーディング(文字コード)の問題が有る。Windows ではシフトJIS(SJIS)と謂うエンコーディングを使用するが、UNIX では EUC(EUC-JP)が使用さ れ、亦、電子メール等は所謂JIS(ISO-2022-JP)エンコーディングを使用して居る。 猶、日本語のエンコーディングはSJIS、EUC-JP、ISO-2022-JP の他、自動判定 JISAutoDetect が有 る。欧米で良く使われるLatin-1 エンコーディングは ISO-8859-1 と指定する。特に日本語と仕て処理 する必要がなければ、此れを指定して読み込むのが安全で有る。
Java では、文字データを Unicode で管理する。ファイル入出力を行う際、Unicode 以外の文字コード を読み込む場合は、読み込みの際にUnicode へエンコードして読み込む。書き込みの場合は、Unicode で管理されて居る文字を他の文字コードへ、エンコードして書き込む。特に指定を行わない場合は、Java を実行して居るシステムのデフォルトのエンコード方式が使用される。デフォルトのエンコード方式は System.getProperty("file.encoding")で調べる事が出来る。 FileReader クラス、FileWriter クラスを使用して文字データの入出力を行う場合、実行して居るシス テムのデフォルトのエンコード方式が使用される。エンコード方式を指定してファイル入出力処理を行 い度い場合はInputStreamReader クラスと FileInputStream クラス、OutputStreamWriter クラスと FileOutputStream クラスを組み合わせて行う。
■ ファイル情報の取得 ■
下記のコードを、テキストエディタで入力し、FileIOinfo.java と謂うファイル名で保存した後、コンパ イルして、実行する。
import java.io.*; public class FileIOinfo {
public static void main(String args[]) {
// File クラスのインスタンスを生成 File f = new File("FileIOinfo.java"); if(f.exists()) { // ファイル情報の表示する System.out.println("ファイル名:" + f.getName()); System.out.println("絶対パス名:" + f.getAbsolutePath()); System.out.println("格納パス名:" + f.getParent()); System.out.println("ファイル長:" + f.length()); System.out.println("最終更新日:" + f.lastModified()); System.out.println("読み込み可:" + f.canRead()); System.out.println("書き込み可:" + f.canWrite()); } else { System.out.println("指定のファイルは存在しません!"); } } } ▼ File クラスには、入出力のエラーを事前に回避する為のメソッドが、数多く用意されて居る。下記 に重要と思われる物を示す(詳細はAPI 仕様書を参照)。 戻り値 メソッド 説明
boolean canRead() ファイルが読込可能ならtrue を返す。 boolean canWrite() ファイルが書込可能ならtrue を返す。 boolean exists() ファイルが存在すればtrue を返す。
boolean delete() ファイル、又は、ディレクトリを削除する。
void deleteOnExit() プログラム終了時に、ファイル、又は、ディレクトリを削除する。 boolean mkdir() ディレクトリを生成する。
boolean renameTo(dest) ファイル名をFile オブジェクト dest が示す名前に変更する。 boolean setReadOnly() ファイル、又は、ディレクトリを読込専用に設定する。 String[] list() ファイル、及び、ディレクトリを表す文字列の配列を返す。 File[] listFiles() ディレクトリ内のファイルの配列を返す。 ※ 最終更新日は、1970年1月1日0時からの経過時間で有る。
演
演
習
習
ファイル情報を取得する為 には、java.io.File クラスを使 用する。同クラスのメソッド は、総てインスタンスメソッ ドで有る為、コンストラクタ を使用してインスタンスを 生成する必要が有る。猶、フ ァイル情報を取得する丈な ので、ファイルのオープンや クローズは不要で有る。■ バイナリファイルの書込 ■
下記のコードを、テキストエディタで入力し、FileIObinaryW.java と謂うファイル名で保存した後、コ ンパイルして、実行する。
import java.io.*;
public class FileIObinaryW {
public static void main(String args[]) { try { int d; // ファイルのオープン
FileOutputStream f = new FileOutputStream("TestFile.bin"); // データの書き込み(1バイト宛書き込む) for(d=0; d<256; d++) { f.write(d); } // ファイルのクローズ f.close(); } catch(Exception e) { System.err.println("例外発生:" + e); System.exit(1); } System.out.println("ファイルの書き込みが完了しました!"); } } ▼ write メソッドを使用すると、ファイルの書込位置が自動的に更新される為、ファイルの先頭から 順番にデータが書き込まれる。猶、write メソッドのパラメータは int 型で有るが、ファイルに書き 込まれるデータは1バイトと成る。 ※ プログラムを強制的に終了するには、System.exit メソッドを使用する。パラメータには、プログラ ムの戻り値を指定する。慣習的に、正常終了時は0 を、エラーの時は 0 以外の適当なエラー番号を 指定する。 ※ ファイル入出力のメソッドの実行の際にチェック例外が発生する可能性が有る為、処理を try 節内に 記述して、例外処理を行う必要が有る。此れは、必須で有る。
※ java.lang.System クラスには、標準入力ストリームの in、標準出力ストリームの out の他に、標準 エラー出力ストリームのerr と謂うフィールドが有る。主な出力ストリームで有る out が、一般的に 継続的には監視されて居ないファイル等にリダイレクトして居る場合でも、ユーザに注意を促す為 のエラーメッセージ等を表示する為に、通例、此の出力ストリームが使用される。 バイナリファイルに書き込 み を 行 う 為 に は 、 java.io.FileOutputStream クラスを使用する。同クラ スのメソッドは、総てイン ス タ ン ス メ ソ ッ ド で 有 る 為、コンストラクタを使用 してインスタンスを生成す る必要が有る。
■ バイナリファイルの読込 ■
下記のコードを、テキストエディタで入力し、FileIObinaryR.java と謂うファイル名で保存した後、コ ンパイルして、実行する。
import java.io.*;
public class FileIObinaryR {
public static void main(String args[]) { try { int d; // ファイルのオープン
FileInputStream f = new FileInputStream("TestFile.bin"); // データの読み込み(1バイト宛読み込む) while((d = f.read()) != -1) { // 16進数で表示する if(d<16) { System.out.print("0" + Integer.toHexString(d) + " "); } else { System.out.print(Integer.toHexString(d) + " "); } if(d % 16 == 15) System.out.println(); } // ファイルのクローズ f.close(); } catch(Exception e) { System.err.println("例外発生:" + e); System.exit(1); } System.out.println("ファイルの読み込みが完了しました!"); } } ▼ read メソッドを使用すると、ファイルの読込位置が自動的に更新される為、ファイルの先頭から順 番にデータが読み出される。亦、read メソッドは、ファイルの終わりに達すると-1 を返す。猶、read メソッドの戻り値はint 型で有るが、ファイルから読み込まれるデータは1バイトと成る。 ※ Java のクラスライブラリには、Java の基本的なデータ型を扱う為のラップクラスが有る。此のク
ラスの一で有るjava.lang.Integer クラスは int 型の整数を扱う為のクラスで、toHexString メソッ ドを使用すると、パラメータで指定した数値を16進数の文字列に変換する事が出来る。 バイナリファイルから読み 込 み を 行 う 為 に は 、 java.io.FileInputStream ク ラスを使用する。同クラスの メソッドは、総てインスタン スメソッドで有る為、コンス トラクタを使用してインス タンスを生成する必要が有 る。
■ バイナリファイルのコピー ■
下記のコードを、テキストエディタで入力し、FileIObinaryC.java と謂うファイル名で保存した後、コ ンパイルして、実行する。
import java.io.*;
public class FileIObinaryC {
public static void main(String args[ ]) { try { int d; // 入力ファイルのオープン
FileInputStream inp = new FileInputStream("TestInp.txt"); // 出力ファイルのオープン
FileOutputStream out = new FileOutputStream("TestOut.txt"); while ((d = inp.read()) != -1) // 入力 { out.write(d); // 出力 } // ファイルのクローズ inp.close(); out.close(); } catch (Exception e) { System.err.println("例外発生:" + e); System.exit(1); } System.out.println("ファイルのコピーが完了しました!"); } }
▼ FileInputStream クラスの read メソッドには、下記のオーバーロード(Overload:多重定義)が有る。
int read() 入力ストリームから、データの次のバイトを入力 int read(byte[] b) バイト配列の要素数丈のバイト数をバイト配列に入力 int read(byte[] b, int off, int len) 読込開始位置と読込バイト数を指定してバイト配列に入力
▼ FileOutputStream クラスの write メソッドには、下記のオーバーロードが有る。
void write( int b) 指定されたバイトを出力ストリームに出力
void write(byte[] b) バイト配列の要素数丈のバイト数を出力ストリームに出力 void write(byte[] b, int off, int len) 書込開始位置と書込バイト数を指定して出力ストリームに出力
※ 此等のオーバーロードは、処理に応じて、使い分ける必要が有る。 バイナリファイルをコピー する為には、読み込む為の java.io.FileInputStream ク ラ ス と 書 き 込 む 為 の java.io.FileOutputStream クラスを使用する。孰れの クラスのメソッドも、総て インスタンスメソッドで有 る為、コンストラクタを使 用してインスタンスを生成 する必要が有る。
■ バイナリファイルのコピー(バッファ利用) ■
下記のコードを、テキストエディタで入力し、FileIObinaryCB.java と謂うファイル名で保存した後、 コンパイルして、実行する。
import java.io.*;
public class FileIObinaryCB {
public static void main(String args[ ]) { try { int d; // 入力ファイルのオープン BufferedInputStream inp =
new BufferedInputStream (new FileInputStream ("TestInp.txt")); // 出力ファイルのオープン
BufferedOutputStream out =
new BufferedOutputStream(new FileOutputStream("TestOut.txt")); while ((d = inp.read()) != -1) // 入力 { out.write(d); // 出力 } // ファイルのクローズ inp.close(); out.close(); } catch (Exception e) { System.err.println("例外発生:" + e); System.exit(1); } System.out.println("ファイルのコピーが完了しました!"); } } ▼ バッファ(buffer)とは、一般に『緩衝装置』の事を謂うが、コンピュータ用語と仕ては、データ を一時的に保存する場所を謂う。通常は、メモリ上に確保される。 ▼ ファイルからの入力の場合は、1 バイト宛ディスクから読むと時間が懸かる為、一度に例えば 2048 バイト読み込んでバッファに保存して置き、二度目からは実際に読むのではなく、メモリからコピ ーして来ると謂う事が行われる。亦、ファイルへの出力も同様で、最初は実際に書き込まずバッフ ァに保存して置き、例えば512 バイトに成ると一気に書き出しを行う。 ▼ バッファリングして居る時は、コード上では入出力が完了して居ても、実際には端数分がメモリに 残存して居る事が有る。此の端数分は、出力ファイルをクローズした時点でディスクに書き込まれ る。クローズを忘れると、ファイルが全部書き終わらない内に終了して仕舞う事が有るので、必ず オープンしたらクローズする習慣を付けて置く必要が有る。 前出のプログラムは、ファイルから1 バイト宛読み書きして居るので、余 り 能 率 的 で は 無 い 。 上 記 の FileInputStream オ ブ ジ ェ ク ト と FileOutputStream オブジェクトを、 夫々れBufferedInputStream クラス と BufferedOutputStream クラスで ラップ(Wrap)すると、バッファリ ングの効果に依り、実行速度が向上 する。
■ バイナリファイルのコピー(コマンドライン引数でファイル名指定) ■
下記のコードを、テキストエディタで入力し、FileIObinaryCBC.java と謂うファイル名で保存した後、 コンパイルして、実行する。
import java.io.*;
public class FileIObinaryCBC {
public static void main(String args[ ]) { if (args.length != 2) { System.err.println("用法:java FileIObinaryCBC 入力ファイル 出力ファイル"); System.exit(0); } try { int d; // 入力ファイルのオープン BufferedInputStream inp =
new BufferedInputStream (new FileInputStream (args[0])); // 出力ファイルのオープン
BufferedOutputStream out =
new BufferedOutputStream(new FileOutputStream(args[1])); while ((d = inp.read()) != -1) // 入力 { out.write(d); // 出力 } // ファイルのクローズ inp.close(); out.close(); } catch (Exception e) { System.err.println("例外発生:" + e); System.exit(1); } System.out.println("ファイルのコピーが完了しました!"); } } ▼ プログラムの実行時に、条件に依りプログラムの動作を制御する場合には、プログラムに対してコ マンドラインで引数を与える方法が有る。Java では、プログラムに引数を与えるには、プログラム の実行開始位置で有るmain メソッドに対して引数を与える形を採る。
▼ main メソッドの String args[ ]は、コマンドライン引数を格納する為の文字列の配列で有る。コマ
ンドライン引数は、左から順に、args[0]、args[1]、args[2]…に格納される。猶、引数の数(上記 の場合は2)はargs.length に依り取得する事が出来る。 前出のプログラムの様に具体的 なファイル名をコード中に記述 すると汎用性が無く成る為、コマ ンドラインでファイル名を指定 する事が出来る様にした例を、下 記に示す。猶、実行するには、コ マ ン ド ラ イ ン で 『 java FileIObinaryCBC 入力ファイル 出力ファイル』の様に入力する。