プログラミング応用b 第7回『ファイル入出力の基礎』07-07. 『ファイル操作(File, FileDescriptorクラス)』 |
■7. 『ファイル操作(File, FileDescriptorクラス)』
■7.1 『Fileクラス』
さて,次にFileクラスを紹介しよう。Fileクラスはストリームではない。ファイルを指定
する場合,多くのオペレーティングシステムでは,パス名(path name)を使う。しかし,
オペレーティングシステムによってパス名の表現方法は異なる。
たとえば,UNIXではすべてのファイルはルートディレクトリ(/)以下に繋がるディレクト
リ木構造に属している。そして,ディレクトリ階層は/で区切られている。dir1,dir2,...,
dirNをディレクトリ名とすると,特定のファイルを指定するパス名は,
/dir1/dir2/dir3/ファイル名
というように,ルートディレクトリから特定のファイルまでのつながりを,/で区切って表
現する。
一方,Windowsでは,ファイルシステムはA:やC:といったドライブごとにディレクトリ木
構造を持っており,ディレクトリ区切りには'\'(欧米系のフォントでは逆スラッシュの文字
で,日本語用フォントでは半角の円マーク文字で表示されることもある)を使う。たとえば,
C:ドライブにあるファイルのパス名は
C:\dir1\dir2\dir3\ファイル名
というように表現する。
Javaは,どのプラットフォーム上でも同じように動作することをその至上命題としている。
そのため,プラットフォームによってパス名の表現が異なることは大きな問題となる。そこ
で,導入されたのがFileクラスである。Fileクラスは,プラットフォームに依存しない,抽象
的なパス名(抽象パス名)を表すクラスなのである。以上のことから,パス名でファイルを指
定するより,いったんFile型オブジェクトを生成して,それを使うようにする方が良い。
また,Fileクラスは,ファイルやディレクトリに関する基本操作も提供してくれる。たとえば,
ファイル名の変更やディレクトリの作成,などなどである。
■7.1.1. 『Fileクラスの機能』
それでは,Fileクラスのメソッドとpublicフィールドを紹介していこう(Table 7)。もちろん,
暗記する必要など無く,「こういうファイル操作ができるんだ!」程度に読み流して良い。
自分のプログラム作成に役立てて欲しい。
まず,コンストラクタだが,パス名文字列 pathname から File型オブジェクトを生成するものや,
親ディレクトリとファイル(ディレクトリ)名の組み合わせで対象となるファイル(ディレクトリ)
を表すFile型オブジェクトを生成するものがある。また, URI で指定されたファイル(ディレ
クトリ)を表す File型オブジェクトを生成するコンストラクタも用意されている。
ファイル(ディレクトリ)が,読み書き可能かを調べるメソッドとして,canRead( ) と canWrite( )
が用意されている。compareTo( ) メソッドや equals( ) メソッドは,File型オブジェクトどう
しの比較に使う。
creatNewFile( ) メソッドは,このFile型オブジェクトが表しているファイルを実際に作成し
ようとする。creatTempFile( ) メソッドは,作業用の一時ファイルを生成する。たとえば,
createTempFile( "MyTemp", ".temp" );
として呼び出すと,一時ファイル用のディレクトリ(たいていオペレーティングシステムごと
にデフォルトの場所が決まっている)内に
MyTemp*******.temp
という形式の一時ファイルを作成する(*******の部分は一意,すなわち他と重ならない唯一
の番号など)。一時ファイルを作成するディレクトリを明示的に指定する版もある。
delete( ) メソッドは,このFile型オブジェクトが表すファイル(ディレクトリ)を削除する。
deleteOnExit( ) メソッドは,仮想マシン終了時にこの File型オブジェクトが表すファイル(デ
ィレクトリ)を削除するように指定する。ファイル(ディレクトリ)が存在するかどうか調べる
のには,exists( ) メソッドが使用できる。
getAbsolutePath( ) や getAbsoluteFile( ) は,このFile型オブジェクトが表すファイル
(ディレクトリ)の絶対パスまたは絶対パス名(File型オブジェクト)を返す。
getCanonicalPath( ) メソッドや getCanonicalFile( ) メソッドは,このFile型オブジェクトが
表すファイル(ディレクトリ)の正規パス名または正規抽象パス名(File型オブジェクト)を返す。
正規パス名とは,一意(「他のものと区別でき,ただひとつ定まる」という意味)のパス名で
,シンボリックリンク(例えば,Windowsにおけるショートカット)などを解決し, ..(親ディレクトリ)
や .(このディレクトリ)といった特別なディレクトリを表す記号を実際のディレクトリに直した
絶対パス名である。
getPath( ) メソッドは単にパス名を返し,getName( ) はファイル名(ディレクトリ名)を返す。
getParent( ) と getParentFile( ) は,それぞれ親ディレクトリのパス名と抽象パス名を返す。
このFile型オブジェクトが指す抽象パス名が絶対パスかどうかを検査するのが,isAbsolute( )
メソッドである。また,File型オブジェクトがディレクトリかどうかを検査をするのがisDirectory ()
である。一方,isFile( )はファイルかどうかを検査する。ファイル(ディレクトリ)が一般ユー
ザから隠されている特殊な「隠しファイル(ディレクトリ)」かどうかを検査するのには,isHidden( )
メソッドが使える。
ファイルの最終更新時刻を得るには,lastModified( ) が利用できる。返り値の時刻は,long型
で,グリニッジ標準時の1970年1月1日0時0分0秒からのミリ秒で表されている。最終更新
時間を明示的に設定するには setLastModified( ) を使う。ファイルの長さを得るには,
length( )を利用できる。
File型オブジェクトの指すディレクトリ内にあるファイル・ディレクトリの一覧を得るには
,list( ) や listFiles() が使用できる。この一覧では,条件にあったものだけをフィルタリング
してリストアップすることが可能である。
フィルタリングを行うためには,インタフェイス FilenameFilter や FileFilter を実装するクラ
スのオブジェクトを使う。FilenameFilter と FileFilter の abstract メソッドを Table 8,Table 9
に示す。これらのインタフェイスは, accept( ) というabstractメソッドを持っており,この
メソッドが true を返すファイルのみがリストアップされることになる。
ファイルシステムのルートをリストアップするには, listRoots( ) を使う。UNIXではルートは
/
だけであるが,Windows ではドライブごとにルートがあるために,複数のルートが
C:\
D:\
というようにリストアップされる。
ディレクトリを作成するには, mkdir( ) メソッドを使う。複数の必要な親ディレクトリも含めて
作成する場合は,mkdirs( ) を用いる。 mkdirs( ) は失敗時であっても,親ディレクトリの
いくつかは作成されていることもありえるので,注意が必要である。
ファイルやディレクトリの名前を変更するには, renameTo( ) を使う。また,ファイルやディレクトリ
を読み込み専用にするには, setReadOnly( ) を利用できる。
抽象パス名を文字列パス名に変換するには,toString( ) を用いる。URIやURLに変換するには,
toURI( ) と toURL( ) を使う。
フィールドとしては,システム依存のパス名のディレクトリ階層の区切りに使う文字を表す
separatorChar と separator がある。また,複数のパス名を併記するときに,パス名の間を区切
る記号もシステム依存で,このパス名の区切り文字は pathSeparatorChar と pathSeparator
に格納されている。
■7.1.2. 『Fileクラスの使用例』
Fileクラスの使用例を List 5 に示す。
List 5 FileTest.java
List 5-<①>でまず必要になるストリーム変数を宣言しておく。
List 5-<2>ではファイルシステムのすべてのルートをリストアップして表示している。
List 5-<3>では,UNIX流に言えば
dir1/dir2/dir3
Windows流に言えば
dir1\dir2\dir3
というディレクトリを作成している。List 5-<4> では,作成した dir3 ディレクトリの下に一時
ファイルを2つ作成している。一時ファイルは,仮想マシンの終了時に自動的に削除されるよう
に設定されている。
次に,作成した一時ファイルにいったん文字列を書き込み(List 5-<5>),書き込んだファイ
ルからまた文字列を読み込んで表示する(List 5-<6>)。
List 5-<7>では,dir3ディレクトリ内のファイル・ディレクトリの一覧を表示している。
List 5-<8>はcatchブロック,List 5-<9>はfinallyブロックである。
■7.2. 『FileDescriptor クラス』
最後に, FileDescriptor クラスを紹介しよう。「ファイルディスクリプタ」と読む。FileDescriptor
は,ファイル記述子という,ファイル(ディレクトリ)のJavaシステム内での表現である。Table 10
にFileDescriptorのメソッドを示す。
通常,ファイル記述子を使う用途は2つだけである。一度オープンした FileInputStream, FileOutputStream,
RandomAccessFileからは getFD( ) メソッドによって FileDescriptor型オブジェクトを得る
ことができる。そして,ほとんどのファイルストリーム(RandomAccessFile を含む)は FileDescriptor型
オブジェクトを引数に指定して生成するコンストラクタを持っている。そのため,あるファイルストリームと
同じファイルを対象とした別のストリームをオープンするのに, FileDescriptor を使用できる。
これが第1の用途となる。
第2の用途は,バッファとファイルの厳密な同期である。一般に,出力ストリームに対して
は flush( ) メソッドを呼んでバッファ上にあるデータをファイルなどに書き込む。しかし,実際
にはプラットフォームのオペレーティングシステムでもバッファリングが行われていることが
多い。つまり,バッファリングは,オペレーティングシステムのレベルと Java のレベルの2重
で行われている可能性がある。
バッファリングがオペレーティングシステムでも行われている場合,Javaのレベルで flush( )
メソッドを呼んでも,実際にはオペレーティングシステムの出力バッファに書き込まれるだけ
で,ファイル上には書き込まれていない可能性もあるわけである。
そこで,確実にデバイス上のファイルにデータをフラッシュして,ファイル上のデータの内
容とバッファ上の内容を同期する手段が必要になる。この確実な同期を行うのが FileDescriptor
の sync( ) メソッドなのである。
よって,確実にバッファの内容をフラッシュしたい場合は,ファイルストリームの getFD( )
メソッド使って FileDescriptor型オブジェクトを取得しておき,その sync( ) メソッドを呼ぶよ
うにすると良い。ただし,フラッシュには時間がかかるので,頻繁な sync( ) メソッドの呼び出
しは実行パフォーマンスを低下させるので注意しよう。
■入出力処理のまとめ
入出力処理がある程度利用できるようになると,プログラミングの幅が広まる。ぜひ積極的
に使ってマスターして欲しい。