[プログラミング演習(Ruby) >  ファイル入出力]

ファイル入出力

標準入出力」の資料でも述べた通り,実用的なプログラムでは,しばしばファイルを介して大量のデータを扱います. ここでは,ファイルからデータを直接入力する,あるいはファイルへデータを直接に出力する方法について解説します.

もくじ

  1. 例題
  2. プログラム
  3. ファイル入出力の概要
  4. ファイルのオープン
  5. ファイルのクローズ
  6. ファイルの読み書きのためのメソッド
  7. ブロックつきメソッドによるファイルの入出力
  8. open/closeによるファイルの入出力の例
  9. 参考:ARGFによるファイルの読み込み

例題

ファイルに含まれる文字の頻度分布を計算し,別のファイルにそのデータを書き出す.

プログラム

例題のプログラムをRubyで記述すると以下のようになります.

cf.rb
[行番号つきプログラムを別のウィンドウで開く] [行番号なしのプログラム]

このプログラムは,たとえば次のように実行します.

$ ruby cf.rb input.txt output.txt
$ xgraph output.txt

1番目のコマンドでinput.txtの文字頻度分布データを生成してoutput.txtに保存しています. 2番目のコマンドのxgraphは2次元グラフ表示ツールです. xgraphでcf.rbが生成するデータ(output.txt)をグラフ化できます.

ファイル入出力の概要

ファイルを介した入出力を行う,つまりファイルからデータを読み出すあるいはファイルにデータを書き出すには,予めファイルと対応づけられた入出力ストリームを準備する必要があります. また入出力が終わってストリームが不要になったときには,後片付けをする必要があります.

ストリームを準備することをオープン(open)する,ストリームを片付けることをクローズ(close)するといいます. たとえばファイルからデータを読み込むには次のようにします.

  1. まずファイルをオープンします.
  2. つづいてオープンされたストリームから実際にデータの読み込みを行います.
  3. 読み込みが完了したらストリームをクローズします.

ファイルにデータを書き込む場合の手順もほぼ同様です.

  1. まずファイルをオープンします.
  2. つづいてオープンされたストリームに実際にデータの書き込みを行います.
  3. 書き込みが完了したらストリームをクローズします.

ファイルのオープン

ファイルをオープンしてストリームを得るにはopenメソッドを使います. openでは,オープンするファイルのパスとモード(mode)を指定します. モードとはファイルの扱い方を示すデータです. ファイルを読み込むために使う場合,ファイルに書き込むために使う場合など,目的に応じてモードを適宜指定する必要があります. モードは文字列で与えます. なおモードを省略すると読み込み専用でオープンすることになります("r"を指定したのと同じ).

  open(ファイル名,モード)
モード意味
"r"読み込み専用モード.指定したファイルがなければエラー
"w"書き込み専用モード.指定したファイルがなければ新たに作成する.すでに存在した場合はファイルをいったん空にする.
"a"追加書き込みモード
"r+"読み書きモード.指定したファイルがなければエラー
"w+"読み書きモード.指定したファイルがなければ新たに作成する.すでに存在した場合はファイルをいったん空にする.
"a+"追加書き込みモード
"b"バイナリモード.他のモードと組み合わせて指定する.テキストファイルとバイナリファイルの扱いに区別があるシステムで利用する.Unix(Linux)ではテキストファイルとバイナリファイルの扱いに区別がないため,このモードを指定する必要はない(指定しても無害)

オープンの返り値はストリームに対応するオブジェクトです.

  f = open("foo.txt","r")
なお,openにより外部コマンドとの間にパイプラインをつくってデータのやりとりをすることもできます.

ファイルのクローズ

ファイルに対する入出力が終わったら必ずクローズします. クローズすることで処理が終わったことがシステムに伝えられます.

  f = open("foo.txt","r")
  :
  f.close # ファイルをクローズする  

ファイルの読み書きのためのメソッド

ストリームに対応するオブジェクトには,たとえばgetsやprintといったメソッドが定義されています. これらはこれまでに関数的メソッド使っていたgets,printと全く同じように使えます. レシーバを指定しなければ,標準入出力を使うことになり,レシーバとしてストリームに対応するオブジェクトを指定すれば,そのストリームに対する入出力を行うことになるわけです.

Rubyにはファイルを読み書きするためのメソッドが他にもいろいろ用意されています. ここでいくつか例を挙げます. 詳しくはRubyのIOクラスのマニュアルを参照してください.

読み込みメソッド
each,each_line一行ずつ読むイテレータ
each_byte1バイトずつ読み込むイテレータ
gets1行読み込む
read指定したバイト数だけ読み込む.バイト数を指定しない場合はすべて読み込む
書き込みメソッド
<<引数に指定したオブジェクトをファイルに書き出す.
print引数として指定したオブジェクトを順に書き出す.
puts引数として指定したオブジェクトに改行をつけてから順に書き出す.
write引数に指定したオブジェクトをファイルに書き出す.

ブロックつきメソッドによるファイルの入出力

openはブロックつきメソッドとして利用することもできます. この場合ブロック内でファイルの処理を行うことになります. ストリームに対応するオブジェクトはブロックパラメタとしてブロックに渡されます. またブロックの実行終了時にファイルが自動的にクローズされます. つまりブロックつきメソッドで処理した場合,closeを明示的に実行する必要がありません. ここで詳細は述べませんが,例外処理を行うことを考えた場合, ブロックつきメソッドで処理した方がプログラムが簡単になります.

例題のプログラムでもブロックつきメソッドで処理を行っています.


20  # 入力ファイルから1文字ずつ読みこむ
21  open(infile,"rb") do |fin|
22    fin.each_byte do |c|
23        dict[c] = dict[c] + 1 # c(cは文字コード)の頻度を1増やす
24    end
25  end
26  
27  # 各文字コードの出現頻度を出力ファイルに書き出す
28  open(outfile,"w") do |fout|
29    dict.each_with_index do |freq,code|
30      fout.print code," ",freq,"\n" 
31    end
32  end

open/closeによるファイルの入出力の例

open/closeを明示的に使ったプログラムの例を挙げます. このプログラムは例題プログラムとほぼ同様のものです. ただし出力ファイルが指定されない,あるいは「"-"」というファイルがしていされた場合には標準出力に結果を書き出すようになっています.

cf2.rb
[行番号つきプログラムを別のウィンドウで開く] [行番号なしのプログラム]

このプログラムは,たとえば次のように実行します.

$ ruby cf2.rb input.txt - |  xgraph 

xgraphはデータファイルが与えられない場合は標準入力からデータを読みます.

参考:ARGFによるファイルの読み込み

RubyにはARGFというオブジェクトが定義されています. さてプログラム実行時にコマンドライン引数としてファイルをいくつか指定したとします. それらのファイルの内容をすべて一列につなげた仮想的なファイルを考えます. ARGFはこのような仮想ファイルに対応するストリームとして働くオブジェクトです. なお引数は実際にファイルであろうとなかろうとファイル名とみなされます(引数がファイルであることを確認するわけではありません). また引数がない場合は,ARGFは標準入力に対応することになっています.

ARGFを利用することで,ファイルが与えられればファイルからデータを読む,そうでなければ標準入力からデータを読むというプログラムを簡単に作ることができます(Unixではこのようなスタイルのプログラムがよく使われます).

ARGFは関数的メソッドであるgetsの隠されたレシーバです. つまり「gets」を「ARGF.gets」と書くこともできます. そこで,例題のプログラムを次のように書くこともできます. このプログラムは複数のファイルを処理することができます.

cf3.rb
[行番号つきプログラムを別のウィンドウで開く] [行番号なしのプログラム]

このプログラムは,たとえば次のように実行します.

$ ruby cf3.rb input0.txt input1.txt |  xgraph 
[プログラミング演習(Ruby) >  ファイル入出力]