ファイル入出力 Ⅰ 今回の課題項目 ファイル入出力 ( 概要 手順 ) ファイル入出力 ( 使用クラス 使用コンストラクタ ) ファイル入出力 ( 文字コード処理 ) ファイル入出力 ( ファイル情報の取得 ) ファイル入出力 ( バイナリファイルの入出力処理 ) 今回の重点項目 ファイル入出力の基本 ( 概要 手順 使用クラス ) ファイル入出力の実践 ( ファイル情報の取得 バイナリファイルの操作 ) -1-
ファイル入出力 ファイル入出力の概要 プログラムを作成する際 或るファイルのデータを読み込み 別のファイルへ書き出す 或るデータを読み込む際 データのフィルタ処理を行う 或るデータの書き込みを 別のプログラムの入力値とする 等と謂う入出力に関する処理を行う事が有る Java では 其等の処理を java.io パッケージに含まれる様々なクラスで対応して居る ファイル入出力の手順 ファイル入出力 (File Input & Output) とは ファイルの内容を読み出したり (Input: 入力 ) ファイルに情報を書き込んだり (Output: 出力 ) する事で有る ファイル入出力を行う為には ファイルに格納されたデータを変数に読み込んだり 変数 ( 又は 定数 ) の内容をファイルに書き込む事に成る ファイル入出力の処理は 概ね 以下の手順で行われる 1 ファイルを開く ( ソースに対し読み込み 又は 書き込みストリームを開く ) 2 データの読み込み 又は 書き込みを行う 3 ファイルを閉じる ( ソースに対し読み込み 又は 書き込みストリームを閉じる ) 猶 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 ブラウザ上で動作するアプレットに付いては セキュリティの観点から ファイルへの入出力は許可されて居ない -2-
コンストラクタ ファイル入出力処理で使用されるクラスの主なコンストラクタを下記に示す FileReader クラス FileReader(File) コンストラクタ FileReader(FileDescriptor) FileReader(String) 説明 引数に読み込むファイルの File オブジェクトを指定する 引数に FileDescriptor オブジェクトを指定する 引数に読み込むファイルのパス名を指定する 例 : ファイルパス名を指定して 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) FileWriter(String) FileWriter(String, boolean) 引数に FileDescriptor オブジェクトを指定する 引数に書き込むファイルのパス名を指定する 引数に書き込むファイルのパス名を指定する 第 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) FileOutputStream(String) FileOutputStream(String, boolean) 引数に FileDescriptor オブジェクトを指定する 引数に書き込むファイルのパス名を指定する 引数に書き込むファイルのパス名を指定する 第 2 引数が true の場合は ファイルの最後からデータを書き込む (Append) -3-
InputStreamReader クラス コンストラクタ説明 InputStreamReader 第 1 引数に読み込む InputStream クラスのオブジェクトを指定する 此の場 (InputStream) 合はデフォルトのエンコード方式が使われる InputStreamReader 第 1 引数に読み込む InputStream クラスのオブジェクトを 第 2 引数にエン (InputStream, String) コード方式を指定する エンコード方式の指定は IANA Charset Registry に記載される文字列を使用する 例 :FileInputStream オブジェクト生成後 FileInputStream オブジェクトとエンコード方式を引数に指定して InputStreamReader オブジェクト abc を生成 FileInputStream abcfile = new FileInputStream("abc.txt"); InputStreamReader abc = new InputStreamReader(abcFile, "EUC-JP"); OutputStreamWriter クラス コンストラクタ説明 OutputStreamWriter 第 1 引数に書き込む OutputStream クラスのオブジェクトを指定する 此の (OutputStream) 場合はデフォルトのエンコード方式が使われる OutputStreamWriter 第 1 引数に書き込む OutputStream クラスのオブジェクトを 第 2 引数にエ (OutputStream, String) ンコード方式を指定する エンコード方式の指定は 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 クラスを組み合わせて行う -4-
演習 ファイル情報の取得 下記のコードを テキストエディタで入力し FileIOinfo.java と謂うファイル名で保存した後 コンパイルして 実行する 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(" 指定のファイルは存在しません!"); ファイル情報を取得する為には java.io.file クラスを使用する 同クラスのメソッドは 総てインスタンスメソッドで有る為 コンストラクタを使用してインスタンスを生成する必要が有る 猶 ファイル情報を取得する丈なので ファイルのオープンやクローズは不要で有る 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 時からの経過時間で有る -5-
バイナリファイルの書込 下記のコードを テキストエディタで入力し FileIObinaryW.java と謂うファイル名で保存した後 コンパイルして 実行する 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(" ファイルの書き込みが完了しました!"); バイナリファイルに書き込みを行う為には java.io.fileoutputstream クラスを使用する 同クラスのメソッドは 総てインスタンスメソッドで有る為 コンストラクタを使用してインスタンスを生成する必要が有る write メソッドを使用すると ファイルの書込位置が自動的に更新される為 ファイルの先頭から順番にデータが書き込まれる 猶 write メソッドのパラメータは int 型で有るが ファイルに書き込まれるデータは 1 バイトと成る プログラムを強制的に終了するには System.exit メソッドを使用する パラメータには プログラムの戻り値を指定する 慣習的に 正常終了時は 0 を エラーの時は 0 以外の適当なエラー番号を指定する ファイル入出力のメソッドの実行の際にチェック例外が発生する可能性が有る為 処理を try 節内に記述して 例外処理を行う必要が有る 此れは 必須で有る java.lang.system クラスには 標準入力ストリームの in 標準出力ストリームの out の他に 標準エラー出力ストリームの err と謂うフィールドが有る 主な出力ストリームで有る out が 一般的に継続的には監視されて居ないファイル等にリダイレクトして居る場合でも ユーザに注意を促す為のエラーメッセージ等を表示する為に 通例 此の出力ストリームが使用される -6-
バイナリファイルの読込 下記のコードを テキストエディタで入力し FileIObinaryR.java と謂うファイル名で保存した後 コンパイルして 実行する 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(" ファイルの読み込みが完了しました!"); バイナリファイルから読み込みを行う為には java.io.fileinputstream クラスを使用する 同クラスのメソッドは 総てインスタンスメソッドで有る為 コンストラクタを使用してインスタンスを生成する必要が有る read メソッドを使用すると ファイルの読込位置が自動的に更新される為 ファイルの先頭から順番にデータが読み出される 亦 read メソッドは ファイルの終わりに達すると -1 を返す 猶 read メソッドの戻り値は int 型で有るが ファイルから読み込まれるデータは 1 バイトと成る Java のクラスライブラリには Java の基本的なデータ型を扱う為のラップクラスが有る 此のクラスの一で有る java.lang.integer クラスは int 型の整数を扱う為のクラスで tohexstring メソッドを使用すると パラメータで指定した数値を 16 進数の文字列に変換する事が出来る -7-
バイナリファイルのコピー 下記のコードを テキストエディタで入力し FileIObinaryC.java と謂うファイル名で保存した後 コンパイルして 実行する 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(" ファイルのコピーが完了しました!"); バイナリファイルをコピーする為には 読み込む為の java.io.fileinputstream クラスと書き込む為の java.io.fileoutputstream クラスを使用する 孰れのクラスのメソッドも 総てインスタンスメソッドで有る為 コンストラクタを使用してインスタンスを生成する必要が有る 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) 書込開始位置と書込バイト数を指定して出力ストリームに出力 此等のオーバーロードは 処理に応じて 使い分ける必要が有る -8-
バイナリファイルのコピー ( バッファ利用 ) 下記のコードを テキストエディタで入力し FileIObinaryCB.java と謂うファイル名で保存した後 コンパイルして 実行する 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(" ファイルのコピーが完了しました!"); 前出のプログラムは ファイルから 1 バイト宛読み書きして居るので 余り能率的では無い 上記の FileInputStream オブジェクトと FileOutputStream オブジェクトを 夫々れ BufferedInputStream クラスと BufferedOutputStream クラスでラップ (Wrap) すると バッファリングの効果に依り 実行速度が向上する バッファ (buffer) とは 一般に 緩衝装置 の事を謂うが コンピュータ用語と仕ては データを一時的に保存する場所を謂う 通常は メモリ上に確保される ファイルからの入力の場合は 1 バイト宛ディスクから読むと時間が懸かる為 一度に例えば 2048 バイト読み込んでバッファに保存して置き 二度目からは実際に読むのではなく メモリからコピーして来ると謂う事が行われる 亦 ファイルへの出力も同様で 最初は実際に書き込まずバッファに保存して置き 例えば 512 バイトに成ると一気に書き出しを行う バッファリングして居る時は コード上では入出力が完了して居ても 実際には端数分がメモリに残存して居る事が有る 此の端数分は 出力ファイルをクローズした時点でディスクに書き込まれる クローズを忘れると ファイルが全部書き終わらない内に終了して仕舞う事が有るので 必ずオープンしたらクローズする習慣を付けて置く必要が有る -9-
バイナリファイルのコピー ( コマンドライン引数でファイル名指定 ) 下記のコードを テキストエディタで入力し FileIObinaryCBC.java と謂うファイル名で保存した後 コンパイルして 実行する 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 FileIObinaryCBC 入力ファイル出力ファイル の様に入力する プログラムの実行時に 条件に依りプログラムの動作を制御する場合には プログラムに対してコマンドラインで引数を与える方法が有る Java では プログラムに引数を与えるには プログラムの実行開始位置で有る main メソッドに対して引数を与える形を採る main メソッドの String args[ ] は コマンドライン引数を格納する為の文字列の配列で有る コマンドライン引数は 左から順に args[0] args[1] args[2] に格納される 猶 引数の数 ( 上記の場合は 2) は args.length に依り取得する事が出来る -10-