9.入出力とパッケージ
2007.04.18 株式会社四次元データ 西谷太郎
この章では、外部のファイルを読み込む機能と、パッケージという仕組みについて説明します。ここではCSVファイルのプログラム内で扱える形での読み込みと、java.ioパッケージのクラスの利用を通して学びます。9.1. 入出力
さてここでは、外部ファイルを読み込む→そこからHumanインスタンスのフィールドに与える値を得る→Humanインスタンスに設定する、という流れで解説していくわけですが、まだ私たちはその「外部ファイル」なるものを用意していません。
というわけで、この場で用意してしまいましょう。今回は、簡単に操作できるということでCSVファイルを使う事にします。CSVファイルというのはComma Separated Valuesの略で、カンマで列が区切られ、改行で行が区切られるというルールで表記されているテキストファイルのことです。エディタで簡単に作れます。
まずは、CSVファイルを用意しましょう。メモ帳などのエディタを使って、次のように書かれたファイルを作ります。
TaroYamada,32 JiroSato,54 HanakoIto,28
三人分の個人情報が書かれていることがお分かりでしょうか?名前や年齢を変えたり人を増減させるのは構いません。ここでの決め事は、名前,年齢の順でデータが並んでおり、各行が一人の人間を表している、ということです。ファイル名はmember.csvとします。
では、このファイルを読み込んでいきます。
Javaではデータの入出力はストリーム(Stream、流れ)という概念で行われます。大体において、ストリームを開く→データがなくなるまで読み込み/書き込みを行う→ストリームを閉じる、という手順で行われます。
ストリームは一般に、取り扱うデータに応じて文字ストリームとバイトストリームに分けられます。テキストファイル用の文字ストリームと、その他プリミティブなデータ用のバイトストリームというように使い分けます。
実際に書いてみます。8章でsetter、getterメソッドを書いたことはひとまず忘れましょう。
import java.io.FileReader; import java.io.BufferedReader; public class CSVReader { public static void main(String[] args) { FileReader reader = new FileReader("member.csv"); BufferedReader br = new BufferedReader(reader); // ここに処理を記述 br.close(); } }
冒頭のimport ○○○;の部分は、一種のおまじないです。例えばこのCSVReaderクラスでは、java.io.FileReader というクラスを利用しますという宣言です。この宣言なしに、例えば、
java.io.FileReader reader = new java.io.FileReader("member.csv");のように完全限定名でクラスを記述することもできるのですが、あまり読みやすいとは言えません。そこで、冒頭で CSVReader クラスで利用している外部のクラスを宣言しておくわけです。
mainメソッドの最初で、FileReader型の変数readerを作り、"member.csv"を引数にとったFileReaderのオブジェクトを作り、readerにその参照値を代入しています。このreaderをすぐにBufferedReaderに、読み込みのスピードを上げるためです。
FileReaderではread()などのメソッドでファイルの内容を呼び出すたびにファイルにアクセスしますが、BufferedReaderをかませることで、一度に一定量を読み込んでおいて、逐次そこからデータを取り出す、という形をとります。文字ストリームは行ごとにまとめて処理するのが一般的です。
この二行を、
BufferedReader br = new BufferedReader(new FileReader("member.csv"));
と、まとめることも出来ます。
これでmember.csvの中身をBufferedReaderであるbrに持たせることが出来ました。あとはこのbrから、生成したHumanインスタンスにデータを渡すことになります。この部分は10章に譲るとして、最後にbrをclose()メソッドで閉じてしまいます。なお入出力ストリームは使用後に必ず閉じるようにしましょう。
ここで紹介したもの以外にも、外部のファイルとして書き出すFileWriterなどのクラスもあります。
入出力については、入出力 IO に詳しく述べてあります。参照してみてください。
9.2. パッケージ
プログラムをたくさん書いていると、だんだんと管理が大変になってきます。こういう時には普通、フォルダを使ってファイルを整理しますね?Javaでもを同じようにプログラムを整理します。但しJavaの世界では、フォルダの代わりにパッケージを使います。
パッケージを使うメリットは、先ほど大雑把に「管理」という言葉を使いましたが、大きく三つ。
クラスファイル分類 ・・・パッケージで分類することで目的のクラスファイルがどこにあるかがわかりやすくなります。クラス名の衝突防止 ・・・同じ名前のクラスファイルがあると、実行時などにエラーが起こることがあります。例えばWindowsでは同じ名前のファイルが同じフォルダに存在すると上書きされてしまいますが、フォルダを分ければそのようなことは起こりません。同様にパッケージを使えば、そのパッケージ内での重複にさえ気を付ければ良くなります。アクセス制御 ・・・パッケージを一つの基準としてアクセス制御を行うことができます。
+-java +-packageA -test.class +-packageB -test.classこの様にパッケージ分けをすればtest.classという名前がかぶっても大丈夫ですね。
さてパッケージを使うには具体的にどうするのでしょうか。
まず、プログラムの一番初めにパッケージ名を明示します。ここまでのファイルをすべて、自分で作成したintroductionパッケージ(※)に分類することにすると、その中に含まれるすべてのプログラムの先頭に
package introduction;
と、記述することになります。ここでは、HumanとCSVReaderです。(必要ならStudentにも)
また、パッケージは必ずフォルダと対応していなければなりません。フォルダと対応してさえいれば、階層を深くすることもできます。
クラスファイルを作成するときにはパッケージを指定するのが一般的ですが、ここまででは指定しなくてもきちんと動作するプログラムを作ることは一応できました。その場合は「無名パッケージ」を指定したと解釈され、無名パッケージ内の他のファイルからは参照できますが、無名パッケージ外からは参照できません。
また、他のパッケージのからクラスファイルを参照するときには、完全限定名(Fully Qualified Name)を使います。そのファイルを含んでいるパッケージをすべて記述します。上記のtestファイルだと、java.packageA.testとか、java.packageB.testのようにピリオド(".")で区切って上の階層のパッケージから順に中に入っていきます。
ここで使っているFileReaderクラスとBufferedReaderクラスは、java.ioパッケージ内に入っている、もともと提供されているクラスです。ですから本来は、
java.io.FileReader reader = new java.io.FileReader("member.csv"); java.io.BufferedReader br = new java.io.BufferedReader(reader);
の様に記述しなければなりません。が、毎度毎度これを全部書くのはプログラムが大きくなればなるほど大変な手間です。そこで、import文を使ってこの記述を省略する方法が提唱されています。使い方は、パッケージ指定の後に、
import ○○.○○....; import java.io.FileReader; import java.io.BufferedReader;
の様に記述します。一度記述すると、それ以降ここでインポートしたクラスは完全限定名で指定しなくても使うことができます。また、
import java.io.*;
の様に記述すると、java.io内のクラスファイルをすべて使うことができるようになります。ただしこの方法はどのクラスを使用するのかが分かりにくくなるため、あまり推奨されていません。
importが使えないときもあります。別パッケージで、同じ名前のクラスがあり、それらを同時に使用したいときは、少なくとも一方は完全限定名で指定しなければなりません。つまり上記の例をで見ると、
import java.packageA.test import java.packageB.test
の様にしてtestを利用することは出来ず、少なくとも一方は諦めて完全限定名で使用することになります。
また、例外があり、java.langパッケージに含まれるクラスに関しては、import文を省略しても構わないことになっています。
(※作ったプログラムを公開する場合、パッケージ名は世界的に一意なものでなければなりません。そこで、自分の所属するドメインを逆順にしたものを使うことが推奨されています。このサイトであれば、com.techscore.○○○となります。)