-title: ファイル操作とファイル・システム --目的 この実験では、Unixのシステム・コールを通じて、ファイル・システム の利用について学ぶ。具体的には、ファイルの作成、書き込み、 読み込み、開く閉じる操作および、ディレクトリの読み込み操作 について実習を行う。同時に、標準入出力の概念を学ぶ。 --関連科目 情報204 オペレーティングシステム 必修、2単位 ---Java言語 Java 1.7 を使用する。 Java は、どのようなOSでもアーキテクチャでも、同じように動作する ことを目標としている。しかし、ファイル名などには、いくつかの システム依存性が残っている。 Java に関する可搬性(portablity)を意識したプログラミングを行う こと。複数のOS (Mac OS X, Liux, Windows)でテストすることが望ましい。 Java では、Eclipse および ant を利用してプログラムを行うこと。Eclispse で動作するだけなく、ant による手動構築にも対応するように build.xml をつける。 maven に関しては、以下を参照 maven の使い方 Eclipse が指摘するWaring/Error (赤いマーク、黄色いマーク)はすべて取ること。警告を無視するオプションを使う場合はソースに明示的に無視する理由をコメントで記述すること。 ---報告書 それぞれの実験に付いて、 作成したプログラムへのポインタ 学科のhg に登録し、repositoryに登録し、そのrepository名を示す ssh://futenma.ie.u-ryukyu.ac.jp//net/home/hg/y08/e05.../... futenma:/net/home/hg 課題/問題毎に repository その説明(説明に必要なソースのコピーは最小限にすること) (build.xmlについても説明すること) および、 その実行結果を付けなさい。 この実験では、プログラムの説明では、フローチャートを付加する 必要はない。開発環境と実行環境 (計算機、オペレーティング・ システムのバージョン、コンパイラ)を載せなさい。それぞれの 実験について、プログラム作成に要した時間を書きなさい。 ---一般的な注意 報告書は、日本語または英語で記述すること。プログラム、 表、図、数式の羅列は、報告書とは認めない。図は必ず 本文から参照すること。数学における証明のように、 示すべき結論、用いる仮定と前提、推論の詳細について 論理的に記述しなさい。 メールはHTMLで送らない。ソースのencodingは、UTF-8 を使う。 --source の場所 ソース scp -r urasoe.ie.u-ryukyu.ac.jp:~kono/public_html/lecture/os/ex/file-java/src . とかで取って来て下さい。 --ファイルの作成と読み書き Java のクラス fileExample.Copy と fileExample.StdoutCopy は、いずれもファイルのコピーを行う プログラムである。それぞれの使い方を、以下に示す。 % java fileExamle/Copy 既存のファイル 新しいファイル % % java fileExamle/StdoutCopy < 既存のファイル > 新しいファイル % このように、fileExample.Copy は、引数で指定されたファイルを開き、 その内容をコピーするプログラムである。fileExample.StdoutCopy は標準入力 で指定されたファイルの内容を標準出力で指定されたファイルへ コピーするプログラムである。 以下に fileExample.Copy.java のプログラムを示す。 package fileExample; import java.io.*; 必ず、新しいパッケージを定義してから始めよう。このpackageの 作成は、Eclipse のFile Menu の new Menu の Package を使う。 File()クラス、FileReaderクラスを使うためには、java.io パッケージ を使う必要がある。 Java API に関する情報は、 JavaTM 2 Platform Standard Edition 6.0 API Specification から調べること。 /** * @author kono * * Simple File Operation using Java language * 2006/10/1 */ public class Copy { static final int BUFSIZE = 4096; Package の中のクラスを定義する。クラスの中で使用する定数は、 final を使って定義する。ここでは、static は「クラス全部 に定義する」というような意味となる。 コメントは、JavaDoc ツールに適合するように付ける。これも、 Eclipse の機能を用いて作成することも出来る。 /** * @param args * @throws IOException * * File copy */ public static void main(String args[]) throws IOException { main method を定義している。ここでの static は、class method 、 つまり、インスタンスを生成せずに呼び出すサブルーチンとして、 method を定義することを表している。 IOException は、このメソッドの中で使用するAPIが生成するが、 ここでは受けない。 コピーするファイルが存在しなかった場合、コピーする行き先のファイルが なんらかの理由で、書込出来ない場合について、どのようなエラーが 起きるのが観察せよ。 また、それらのエラーをtry {} を用いて、自分で処理する部分を追加せよ。 --Hint. Eclipse を使った場合、実行時の引数は、Run... メニューのargumentss で指定する。 テストファイルなどは、相対パスで指定する場合は、workspace のProject 直下 からの相対パスとなる。 ---標準入出力を使ったコピー fileExample.StdoutCopy は、標準入力で指定された ファイルの内容を標準出力で指定されたファイルへコピーする プログラムである。 package fileExample; /* * StdoutCopy.main -- 標準入力から標準出力へのコピー */ import java.io.IOException; public class StdoutCopy { static final int BUFSIZE = 4096; /** * @param args * @throws IOException * @throws IOException * * File copy */ public static void main(String args[]) throws IOException { int len; byte[] buf = new byte[BUFSIZE]; while((len=System.in.read(buf,0,BUFSIZE))>0) { System.out.write(buf,0,len); } System.out.close(); } } このプログラムは、引数を取らない。"<"や">"は、シェルにより 解釈され、このプログラムには、既に開いたファイルのファイル記述子 (0番と1番)として渡される。 fileExample.Copy とは違って、fileExample.StdoutCopy では、 ファイルを開く操作(File, FileReader) を行うことなく、入出力(read(),write())を行っている。このような事が可能 な理由は、Javaでは、InputStream/OutputStream in, out, err は、Java VMにより開かれているからである。 fileExample.Copy と fileExample.StdoutCopy へのRunを Eclipse に 定義して実行してみよ。 また、java コマンドを直接使って、以下のように実行してみなさい。 % java fileExample/Copy 既存のファイル 新しいファイル % % java fileExample/StdoutCopy < 既存のファイル > 新しいファイル fileExample.StdoutCopy を使ってファイルをコピーするためには、 上で示したようにシェルの標準入出力切り替え機能を使わなけれ ばならない。 ---課題1 tee プログラム fileExample.Copy , fileExample.StdoutCopy の二つのクラスを参考にして、UNIXの tee プログラムと同じ機能を 持つクラスを作りなさい。 その骨組みを fileExample.Tee に示す。今回は、char を使わずに、ByteBuffer を持ちたい。 Buffered I/O のversion と、Unbuffred のversionの二つを作り、速度を 比較しよう。 --ファイルの属性 UNIXでは、stat() (あるいは、lstat(),fstat() )システム・コールを 用いてファイルの属性(ファイルの管理情報)を調べることができる。 これはシステム依存であり、Java には、それに対応するAPIが用意されている。 ファイルの属性を調べ、画面に出力するプログラムを fileExample.Stat に示す。 package fileExample; import java.io.*; /** * @author kono * * Simple File Operation using Java language * 2006/10/1 */ public class Stat { /** * @param args * @throws IOException * * File stat */ public static void main(String args[]) throws IOException { File file; System.out.println(args[0]); file = new File(args[0]); if (! file.exists()) { System.out.println(" does not exist."); return; } printStat(file,System.out); } public static void printStat(File file,PrintStream out) { out.println(file.getAbsolutePath()); if (file.isDirectory()) { out.println(" isDirectory"); } if (file.canRead()) { out.println(" can read"); } else { out.println(" cannot read"); } if (file.canWrite()) { out.println(" can write"); } else { out.println(" cannot write"); } out.print("length = "); out.print(file.length()); out.println(); out.print("last modified = "); out.print(file.lastModified()); out.println(); } } Eclipse を使ってコンパイルして、実行して見なさい。引数として、 適当なファイルを指定すること。 出力について、Java APIにそって解説せよ。 ---課題 3 modified time last mofidied は、long 型を返す。これは時間である。この時間を 通常使われる時間(日本時間)に直す方法を調べよ。 また、日本時間を表示するように、前のプログラムを手直しせよ。 ヒント: java.util の Calendar クラスを用いる。 ---課題4 ディレクトリの内容 File クラスは、ディレクトリの中身を見ることにも使うことが できる。 fileExample.Stat クラスを使用して、ディレクトリの中に あるファイルをそれぞれStat するクラスを作成せよ。 Arrays クラスを用いて、(名前や大きさで) sort するオプションをつけること。 (Unix では、一見、既にソートされているように出力されるが、 仕様上は、ソートは保証されていない) --Hint. class Arrays static void sort(T[] a, Comparator c) Sorts the specified array of objects according to the order induced by the specified comparator. を使うこと。 class by_period implements Comparator { public int compare(Task q,Task r) { return q.period==r.period?0:q.period > r.period?1:-1; } } というような形で Inner Class でComparatorを定義してやると良い。 --ディレクトリの検索 fileExample.Dir は、ディレクトリの内容を表示させる クラスである。 package fileExample; import java.io.*; /** * @author kono * * Simple File Operation using Java language * 2006/10/1 */ public class Dir { /** * @param args * @throws IOException * * File listing */ public static void main(String args[]) throws IOException { File file; System.out.println(args[0]); file = new File(args[0]); if (! file.exists()) { System.out.println(" does not exist."); return; } if (file.isDirectory()) { String[] list; list = file.list(); // // fill it by yourself // } Stat.printStat(file,System.out); } } ---課題5 ディレクトリの内容の検索 与えられたディレクトリの中から与えられた名前のファイルを検索し、その 絶対パスと、ファイルの長さを表示するクラスを作りなさい。そのクラスの名前を DirLookup とする。DirLookup の実行例を示す。検索は、正規表現を許す こと。 % java fileExample/DirLookup '?*.html' hoge.html 2344 ヒント: File.list(FilenameFilter filter) とjava.util.regex を使う。 ---課題7 Binary Data の読み書き Java nio の Class ByteBuffer 用いて、Binary Data の交換をしたい。 getInt(), putInt() を使って、今日の日付と時間を書き出そう。 C のversion との互換性を維持するにはどうすれば良いか? Mac 及び Linux でテストせよ。 encoding には、UTF-8 を用いること。 参考 http://www.javainthebox.net/laboratory/JDK1.4/NewIO/Buffer/Buffer.html