Lesson 5: ファイル操作
今回は、プログラミングにおいて忘れてはいけないファイルの操作について説明します。
そうね、ファイルの読み書きやログファイルの操作って必要よね。
(いつも通りこの色は美樹ちゃん)
それから、今まで省略してきた例外処理についても少し触れてみます。
Section 1: アプリケーションからファイルをアクセスする
ファイルの入出力などを取り扱うには、java.io パッケージを利用します。これらのパッケージは、外部ファイルや記憶装置などに対してデータの入出力が行えます。
Lession 4 で用いたプログラムを、ボタンを押したら入力したメッセージをファイルに書き込み、その後すぐに同じファイルから内容を出力するプログラムに改変します。
// Import Statements import java.awt.Color; import java.awt.BorderLayout; import java.awt.event.*; import javax.swing.*; import java.io.*; class FileIO extends JFrame implements ActionListener { // Instance Variables (Field) JLabel text; JButton button; JPanel panel; JTextField textField; private boolean clickFlag = true; // Constructor FileIO() { text = new JLabel("Please type a message:"); button = new JButton("Save Messages: text.txt"); button.addActionListener(this); textField = new JTextField(25); panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.setBackground(Color.white); getContentPane().add(panel); panel.add(BorderLayout.NORTH, text); panel.add(BorderLayout.CENTER, textField); panel.add(BorderLayout.SOUTH, button); } // Event Handling public void actionPerformed(ActionEvent event){ Object source = event.getSource(); if (source.equals(button)) { String messages = null; if (clickFlag){ // Write to file try { String text = textField.getText(); String oFileName = "text.txt"; FileOutputStream out = new FileOutputStream(oFileName); PrintWriter outpw = new PrintWriter(new OutputStreamWriter(out, "Shift_JIS")); outpw.println(text); outpw.close(); out.close(); } catch(java.io.IOException e) { System.out.println("Cannot write to text.txt"); } // Read from file try { String iFileName = "text.txt"; FileInputStream in = new FileInputStream(iFileName); BufferedReader inbr = new BufferedReader(new InputStreamReader(in, "JISAutoDetect")); messages = inbr.readLine(); inbr.close(); in.close(); } catch(java.io.IOException e) { System.out.println("Cannot read from text.txt"); } // Clear text field textField.setText(""); // Display text read from file text.setText("Retrieved from file: text.txt"); textField.setText(messages); button.setText("Reset"); clickFlag = false; } else { // Save text to file text.setText("Please type a message:"); textField.setText(""); button.setText("Save Messages: text.txt"); clickFlag = true; } } } // Main Method public static void main(String[] args) { FileIO frame = new FileIO(); frame.setTitle("File IO Sample"); WindowListener winListener = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; frame.addWindowListener(winListener); frame.pack(); frame.setVisible(true); } }
ソースをコンパイルして実行すると、以下の画面が表示されます。
起動時の画面です。 | ||
真ん中のフィールドにメッセージを入力し、"Save Messages"ボタンをクリックします。text.txt ファイルに、入力したメッセージが書き込まれます。 | ||
text.txt ファイルに書き込まれたメッセージを読み込み表示しています。 |
Section 2: ファイルの入出力
フィールドやコンストラクタは、前回にくらべテキストフィールドに関するコンポーネントが増えています。
textField = new JTextField(25);
大きな変更はファイルの操作に関する部分である actionPerformed
で、それ以外の部分は特に難しい変更はしていないので説明を省略します。
// Event Handling public void actionPerformed(ActionEvent event){ Object source = event.getSource(); if (source == button) { String messages = null; if (clickFlag){ // Write to file try { String text = textField.getText(); String oFileName = "text.txt"; FileOutputStream out = new FileOutputStream(oFileName); PrintWriter outpw = new PrintWriter(new OutputStreamWriter(out, "Shift_JIS")); outpw.println(text); outpw.close(); out.close(); } catch(java.io.IOException e) { System.out.println("Cannot write to text.txt"); } // Read from file try { String iFileName = "text.txt"; FileInputStream in = new FileInputStream(iFileName); BufferedReader inbr = new BufferedReader(new InputStreamReader(in, "JISAutoDetect")); messages = inbr.readLine(); inbr.close(); in.close(); } catch(java.io.IOException e) { System.out.println("Cannot read from text.txt"); } // Clear text field textField.setText(""); // Display text read from file text.setText("Retrieved from file: text.txt"); textField.setText(messages); button.setText("Reset"); clickFlag = false; } else { // Save text to file text.setText("Please type a message:"); textField.setText(""); button.setText("Save Messages: text.txt"); clickFlag = true; } } }
textField
に入力された文字列を取り出します。
String text = textField.getText();
書き込み用にファイルを用意しますが、サンプルプログラムのようなファイルの指定ではプログラムを実行したディレクトリーにファイルが作成されます。
String outputFileName = "text.txt";
ファイルの場所を指定する場合、System.getProperty
メソッドや File.separatorChar
利用してシステムに依存しないディレクトリーを指定できます。
String outputFileName = System.getProperty("user.home") + File.separatorChar + "text.txt";
上記のような指定のとき、ユーザーアカウントが shin なら以下のように解釈されます(例)。
UNIX | /home/shin/text.txt |
Windows xp | C:\Documents and Settings\shin\text.txt |
通常、ファイルの入出力を行うには、FileInputStream/FileOutputStream
などといったクラスを利用してファイルを開き、メッセージを read/write
メソッドなどを使用して読み書きをし、close
メソッドを使用してファイルを閉じます。しかし、テキストファイルを扱う場合、Javaの内部で扱っているUNICODEから JIS, Shift_JIS, EUC-JPなど必要に応じて変換しなくてはならないときがあります。その場合、InputStreamReader/OutputStreamWriter
クラスを利用します。このサンプルでは、変換を行うことがあることを考慮してInputStreamReader/OutputStreamWriter
クラスを利用しています。システムデフォルトのコードを利用するので変換の必要が無というなら、InputStreamReader/OutputStreamWriter
クラスを使う必要はありません。
ファイルにメッセージを書き込むには、FileOutputStream
クラスを利用して書き込み用のファイルを指定し、OutputStreamWriter
クラスを使用して文字コードを変換します。その後、write
メソッドを使って文字をファイルに書き込んでも良いのですが、パフォーマンスなどを考慮してBufferedWriter
クラスや PrintWriter
クラスを用います。テキストファイルの出力は、このパターンを覚えておくと良いかもしれません。
FileOutputStream out = new FileOutputStream(oFileName); OutputStreamWriter outw = new OutputStreamWriter(out, "Shift_JIS"); PrintWriter outpw = new java.io.PrintWriter(outw);
これは、実際には効率を良くするためラッピングを利用して以下のように記述します。
PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(oFileName), "Shift_JIS"));
同じように、ファイルからメッセージを取り出すには、FileInputStream
クラスを利用して読み込み用のファイルを指定し、InputStreamReader
クラスを使用して文字コードを変換します。その後、read
メソッドを使って文字をファイルに書き込んでも良いのですが、パフォーマンスなどを考慮して BufferedReader
クラスを用います。テキストファイルの入力は、このパターンを覚えておくと良いかもしれません。
FileInputStream in = new FileInputStream(itFileName); InputStreamReader inr = new InputStreamReader(in, "JISAutoDetect"); BufferedReader inbr = new BufferedReader(inr);
これは、実際には効率を良くするためラッピングを利用して以下のように記述します。
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(iFileName), "JISAutoDetect"));
サンプルでは、見やすくするためにラッピングを数回に分けて記述しています。
日本語の文字コード(charset) についてリストを作っておきます。詳細は Java のサイトにあります。
ISO-2022-JP ISO2022JP |
JISコード(ISO-2022-JP) |
Shift_JIS SJIS |
シフトJISコード |
EUC-JP EUC_JP |
日本語EUCコード |
UTF-8 | Unicode(UTF-8 |
UTF-16 | Unicode(UTF-16) |
JISAutoDetect | 文字コードの自動判定(Readerクラスのみ利用可) |
その後は、作成したファイルのオブジェクトに対してreadLine
メソッドやprintln
メソッドによりメッセージの読み書きを行っています。最後に close
メソッドでファイルをクローズします。
Section 3: 例外処理
例外処理とは、プログラムを安全に実行させていくために、遭遇するかもしれないエラーを処理することです。try - catch
というブロックを利用することで例外処理を記述することが出来ます。try ブロックで記述された処理でエラーが発生した場合、それに応じた例外が発生します。その例外を catch ブロックで処理します。発生した例外に対する catch ブロックが存在しない場合、例外を処理することが出来ません。
サンプルでは、java.io.IOException
という入出力に関する例外すべてを拾っています。
Section 4: アプレットでファイルをアクセスする
アプレットでは、通常クライアントのファイルをアクセスすることが出来ません。クライアントのファイルをアクセス可能にするには、ポリシーを設定する必要があります。セキュリティー上、クライアントのファイルをアクセスさせるアプレットの利用には注意が必要です。
// Import Statements import java.awt.Color; import java.awt.BorderLayout; import java.awt.event.*; import javax.swing.*; import java.applet.Applet; import java.io.*; public class FileIOApplet extends JApplet implements ActionListener { JLabel text; JButton button; JPanel panel; JTextField textField; private boolean clickFlag = true; public void init() { getContentPane().setLayout(new BorderLayout(1, 2)); getContentPane().setBackground(Color.white); text = new JLabel("Please type a message:"); button = new JButton("Save Messages: text.txt"); button.addActionListener(this); textField = new JTextField(25); getContentPane().add(BorderLayout.NORTH, text); getContentPane().add(BorderLayout.CENTER, textField); getContentPane().add(BorderLayout.SOUTH, button); } public void start() { System.out.println("starting..."); } public void stop() { System.out.println("stopping..."); } public void destroy() { System.out.println("destroying..."); } public void actionPerformed(ActionEvent event){ Object source = event.getSource(); if (source.equals(button)) { String messages = null; if (clickFlag) { try { // write to file String text = textField.getText(); String outputFileName = "text.txt"; FileOutputStream out = new FileOutputStream(outputFileName); PrintWriter outpw = new PrintWriter(new OutputStreamWriter(out, "Shift_JIS")); outpw.println(text); outpw.close(); out.close(); // read from file String inputFileName = "text.txt"; FileInputStream in = new FileInputStream(inputFileName); BufferedReader inbr = new BufferedReader(new InputStreamReader(in, "JISAutoDetect")); messages = inbr.readLine(); inbr.close(); in.close(); } catch(java.io.IOException e) { System.out.println("Cannot access text.txt"); } // Clear text field textField.setText(""); // Display text read from file text.setText("Retrieved from file: text.txt"); textField.setText(messages); button.setText("Reset"); clickFlag = false; } else { // Save text to file text.setText("Please type a message:"); button.setText("Save Messages: text.txt"); textField.setText(""); clickFlag = true; } } } }
アプレットの実行には、実行するクラスファイルの指定やパラメータ等を定義した HTMLファイル(fileio.html
)が必要になります。
<HTML> <BODY> <APPLET CODE="FileIOApplet.class" WIDTH="200" HEIGHT="100"> </APPLET> </BODY> </HTML>
さらに、クライアント側のファイルをアクセスするためポリシーの設定(policy.txt
)が必要になります。
grant { permission java.io.FilePermission "text.txt", "read, write"; };
Java対応のブラウザ(Javaの実行が可能な状態になっている)にそのまま読み込ませるか、appletviewer
を使って実行します。
D:\tmp> appletviewer -J-Djava.security.policy=policy.txt fileio.html starting...
起動時の画面です。 | 真ん中のフィールドにメッセージを入力し、"Save Messages"ボタンをクリックします。text.txt ファイルに、入力したメッセージが書き込まれます。 | text.txt ファイルに書き込まれたメッセージを読み込み表示しています。 |
ウィンドウを閉じてアプレットを終了する。
stopping... destroying... D:\tmp>
ここでは、すべて "D:\tmp
"ディレクトリーで作業しているのでポリシーの設定をカレントファイルに対して行っていますが、実際には policytool
コマンドを使用してポリシーの設定を行ってください。