7 ファイルの入出力

ファイルの入出力
これまで作成してきたプログラムでは、キーボードからデータを入力し処理結果を画面に出力し
てきた。しかしながら、コンピュータのディスク装置などにファイルとして保存されているデータ
を読み込んだり、処理結果をファイルに保存しておきたいケースも多い。このような場合、プログ
ラムから、ファイルを開いてデータを読み込み、処理結果をファイルに書き込みファイルを閉じる
というような操作を行うことになる。
ファイルの中身
例えば、文章などのテキストデータが入っているファイルを考える。図 $./ に示すような $
行の文章は、ファイルの中では同図 . / に示すように文字コードが一列に並んだ形で格納される。
このように、文字コードが順番に一列に並んだものをテキストストリーム と呼ぶ。
テキストストリームでは、行の区切りを表すために改行文字 .I9"I# 文字コードは =/ が用
いられる。テキストエディタや コマンドでは、この改行文字を解釈して、図 $./ のように
表示してくれる。
\
(a)
\
(b)
図 ) テキストファイル
ファイルの基本操作
ファイルのオープン 開く とクローズ 閉じる
ファイルに対する入出力を行うためには、まず、ファイルを開く .
"/ 必要がある。1 言語で
は、NK 型へのポインタ変数を宣言し、
" 関数を用いて次のような形でファイルを開くこと
が出来る。
‥‥
ADG@ に必要なヘッダファイル
は ADG@ 型へのポインタ
‥‥
+ &ファイル名 モード'
ファイル名、モードは文字列で与える
NK 型はファイルの情報を管理し入出力を可能とするための構造体で、 NK 型へのポインタ
.ファイル・ポインタと呼ぶ/ を用いてファイルへのアクセスが行われる。
ファイルからデータを読み込むために開く場合は、モードに「44」を指定する。ファイルにデー
タを書き込むために開く場合は、モードに「44」を指定する 。
では改行文字として"#" を用いるが、:'; では行の区切りを表すために"#" "#" の 文字が用いられ
る。"#" の文字コードは +' である。+ や +' は各々
" 進数の 進数の ( ' 進数の を表して
いる。
$$は ' の頭文字、$%$は ;$ の頭文字。これ以外にも、読み書きが可能なモードや追記モードなどもある。
読み込みモードで開く場合、指定したファイルが存在しなければ、
" は JKK を返す。これ
は " が失敗したことを意味する。
書き込みモードで開く場合、指定したファイルが存在しなければ、指定した名前のファイルを新
たに作成し、それが開かれる。ファイルが存在する場合は、ファイルの中身を消去した状態で開か
れる。
これらをまとめると、表 % のようになる。
表 ) *$ の成功と失敗
読み出しモード 失敗
が返る
ファイル無し
ファイル有り
成功
書き込みモード 成功
ファイルを新たに作成
成功
ファイルの中身は消去される
なお、ファイルやディレクトリに対するアクセス権限等の関係で " に失敗する場合もあ
るが、そのような場合も " は JKK を返す。
" で開いたファイルに対する入出力が終了したら、
&'
は で得られたファイル・ポインタ
により、ファイルを閉じる。
文字単位の入出力
【 文字入力】
ファイルから 文字 . バイト/ 読み込むには、
./ 関数を用い、次のように行う。
‥‥
+ L&'
は で得られたファイル・ポインタ。
L は読み込んだ文字のコードを返す。
./ は、ファイル・ポインタ が指すファイルから、 文字 . バイト/ 読み込みその文
字コード . バイトのデータ/ を返す。読み込む文字が無くなったら、
./ は「D」を返
す。D は「"* D !
」の意味で、ファイルの終わりを示す特殊なコードである。 バイト文
字は 型で表現出来るが、
は D のような特殊なコードも返す必要があるため、"
型の値を返す 。
プログラム例 $ は、指定されたファイルを開き、 文字ずつ読み込んでファイルに含まれる文
字数を数えるプログラムである。プログラムでは、" 型変数 " を に初期化し、ファイル
の終わりに達するまで 文字読み込むたびに " を つ増やしている 。
存在しないファイルの中身は読み込めない。
読み込み禁止や書き込み禁止等
ここでの「
文字」は #0 コードなどのいわゆる バイト文字を意味する。日本語などの1文字は複数バイトで表
現されるため、複数回読み込む必要がある。
通常 <= は $'6- の中で>
と定義されている。
%1$ は文字を 31' -符号無 - 型。表せる値は 進数表記で ∼
返す。読み込む文字が無くなれば <=>
を返す。
「改行文字 "#"」などのいわゆる制御文字も 文字として数えている。
として読み、$ にキャストして
プログラム例 $
ファイルに含まれる文字数を数えるプログラム L
に必要なヘッダファイル
に必要なヘッダファイル
.;
ファイル名の長さは - 以下と仮定
)&#'
*
"
ADG@ ファイル名を入れる 型配列
はファイル・ポインタ
文字数を数えるための変数
&3入力ファイル名 + 3'
&34
3 '
ファイル名を 型配列 に入力
+ & 33'
読み出しモードでファイルを開く
& ++ HIGG'*
に失敗したらその旨出力しエラー終了
&3ファイル「4
」が開けない53 '
&'
,
,
+ を に初期化
J&L&' K+ @SA'
ファイルの終わりに達するまで 文字ずつ入力して数える
!!
&'
ファイルを閉じる
&3「4
」の中身は4 文字です53 '
&'
【 文字出力】
ファイルへ 文字 . バイト/ 書き込むには、./ 関数を用い、次のように行う。
‥‥
& '
は で得られたファイル・ポインタ。
はファイルへ書き込む文字 &コード'。
プログラム例 $ は、ファイルのコピーを行うプログラムである。この例では、入力ファイルの
終わりに達するまで、
「入力ファイルから 文字読み込み、それを出力ファイルに書き込む」とい
う動作を繰り返している。プログラムでは、 !
文の条件部に「.!
5 ." // O5
D/」と書いているが、これは、「ファイル・ポインタ " が指すファイルから 文字読み込ん
で変数 !
に代入し、その値が D では無い」ことを意味している。
プログラム例 $
ファイルのコピーを行うプログラム .;
ファイル名の最大長は - と仮定
)&#'
*
< "
< "
ADG@ <
ADG@ <
入力ファイル名
出力ファイル名
入力ファイル・ポインタ
出力ファイル・ポインタ
0 言語では、代入操作を行う「!」も演算子として扱われ、加減乗除などと同様に演算結果の値を持ち、
「!」の右辺
の式の値となる。すなわち、4$$ ! %1$ %5 の値は、%1$ %5 が返す値となる。
読み込んだ文字
&3入力ファイル名 + 3'
&34
3 <'
入力ファイル名を 型配列 < に入力
< + &< 33'
読み出しモードでファイルを開く
&< ++ HIGG'*
に失敗したら、その旨出力してエラー終了
&3ファイル「4
」が開けない53 <'
&'
,
&3出力ファイル名 + 3'
&34
3 <'
出力ファイル名を 型配列 < に入力
< + &< 3J3'
書き込みモードでファイルを開く
&< ++ HIGG'*
に失敗したら
&3ファイル「4
」が開けない53 <'
その旨出力し
&<'
既に開いている入力ファイルを閉じる
&.'
エラー終了
,
入力ファイルの終わりに達するまで、
入力ファイルから 文字読み込みそれを出力ファイルに書き込むことを繰り返す J&& + L&<'' K+ @SA'
& <'
,
&<'
&<'
&'
演習 $ 指定した英語のテキストファイルの中の文字数と行数を数えるプログラムを作成せよ。作
成したプログラムを、ホームページで公開しているファイル 4> を展開して得られる英語の
テキストファイル(4 4 44 44)に適用せよ。
ヒント 文字数を数えるのはプログラム例 を参照。改行文字などの制御文字も
文字として数
える。
ヒント 行末には改行文字I9"I があるので、ファイルに含まれる改行文字の個数を数えれば行数が
分かる。(空行(改行文字のみの行)は
行と数える。行末に改行文字が無いような行は、行とし
て数えない。)
演習 $ 英語のテキストファイルを読み込んで、その中に含まれる小文字をすべて大文字に変換
して出力ファイルに書き込むプログラムを作成せよ。作成したプログラムを、演習 で用いた
4 4 44 44 に適用せよ。
ヒント 変数 に読み込んだ文字が格納されているものとする。 が小文字であるための条
件は、.!
,5 II 77 !
+5 IHI/ で表せる。また、 が小文字の時、それを大文
字に変換するには、 に .IBIII/ を足せば良い。
演習 $$ 指定した英語のテキストファイルに含まれる単語数を出力するプログラムを作成せよ。
ここで、単語とは、空白文字 I I、タブ文字 I9I、改行文字 I9"I 以外の文字の列とする。
作成したプログラムを、演習 で用いた 4 4 44 44 に適用せよ。
ヒント 空白文字、タブ文字、改行文字、H7I を区切り記号と呼ぶ。単語数を数えるには、 つ前
の文字が区切り記号であったかどうかを記憶しておき、現在の文字が区切り記号であるかどうかと
組み合わせて 全部で 通りの組合わせがある 単語数を
時間があれば挑戦してみよう。
増やすかどうかの判定を行えば良い。
書式付入出力
キーボードからの書式付入力は " で行い、画面への書式付出力は " で行えるが、ファ
イルに対する書式付入出力は、 " や " で行うことができる。 " や " は、
各々、" や " にファイルを指定するファイル・ポインタを引数として追加したものになっ
ており、次のような形で使用する。
&< 343 6#'
&< 3453 #'
ファイル・ポインタ < が示すファイルから
進数を読み込みその値を変数 # に代入
ファイル・ポインタ < が示すファイルに対して
変数 # の値を 進数で出力してから改行文字を出力
" でファイルからデータを読み込む際に、ファイルの中にデータが残っていない .既に全
てのデータを読み込んだ状態/ 場合、" は D を返す。
プログラム例 $$ は、ファイルに書かれている 進数データを全て読み込んで、読み込んだデー
タの個数とデータの総和をファイルに出力するプログラムである。
プログラム例 $$
ファイルに格納された 進数データの個数と総和を求めファイルに出力するプログラム L に必要
に必要
.;
ファイル名の最大長!
)&#'
*
< "
< "
ADG@ <
ADG@ <
)
入力ファイル名
出力ファイル名
入力ファイル・ポインタ
出力ファイル・ポインタ
ファイルから読み込んだ 進数
データ数
総和
&3入力ファイル名 + 3'
&34
3 <'
入力ファイル名を < に入力
< + &< 33'
ファイルを読み出しモードで開く
&< ++ HIGG'*
に失敗したら、その旨出力しエラー終了
&3ファイル「4
」を開けない53 <'
&'
,
&3出力ファイル名 + 3'
&34
3 <'
出力ファイル名を < に入力
< + &< 3J3'
ファイルを書き込みモードで開く
&< ++ HIGG'*
に失敗したら、
&3ファイル「4
」を開けない53 <'
その旨出力し
&<'
既に開いている < をクローズし
&.'
エラー終了
,
+ ) + 変数 と ) を に初期化
J&
&< 343 6' K+ @SA'*
< から への読み込みに
成功する間
) !+ ) にそのデータを加え
!!
を 増やす
,
求まった と ) の値を 進数で < に出力
&< 345453 )'
,
&<'
&<'
&'
入力ファイルを閉じる
出力ファイルを閉じる
正常終了
実行結果
8 7
9
.O
0
8 ..
入力ファイル名 + 出力ファイル名 + 8 :
8
囲 刻み幅 をファイルから読み込み、計算結果 と 多項式 の値 刻み
幅 をファイルに書き込むプログラムを作成せよ。
演習 $% 多項式の値を求める演習 において、多項式の次数 多項式の係数 : ; 範
標準入出力
1 言語のプログラムでは、あらかじめ % つのファイルが開かれた状態で " 関数が呼び出され
る。これらのファイルは標準入力# 標準出力# 標準エラー出力と呼ばれる。これらの % つのファ
イルのファイル・ポインタは、各々、*"# *# *
の名前が付けられている。標準入
力からの入力は、通常のファイルからではなくキーボードから行われる。標準出力と標準エラー出
力への出力は、通常のファイルでは無く、画面に表示される 。
キーボードから 文字入力するために「
./」を用いるが、これは、
「
.*"/」と等
価である。また、画面へ 文字 を出力するのに「 ./」を用いるが、これは、
「.#
*/」と等価である。同様に、
「".書式制御文字列# 変数リスト/」は、
「".*#
書式制御文字列# 変数リスト/」と等価であり、「".書式制御文字列# 変数へのポインタのリ
スト/」は、「".*"# 書式制御文字列# 変数へのポインタのリスト/」と等価である。
入出力のリダイレクションとパイプ
./ や "./ 関数を用いて標準入力(キーボード)からデータを入力するように作成
されたプログラム は、プログラム実行時に「 + "<!
」とすることにより、キー
ボードの代わりにファイル "<!
からデータを入力することが出来る。このような方法を入力
多項式の次数、係数、範囲、刻み幅を格納するファイルは で作成すること。
「テキストエディット」や「Æ」
や「Æ」などで作成してはいけない。これらのソフトでファイルを作成すると、ファイル内に様々な制御コード
が埋め込まれる。
標準出力は、通常の出力に用い、標準エラー出力は、エラーメッセージの出力に用いられる
のリダイレクションと呼ぶ。また、 ./ や "./ 関数を用いて標準出力(画面)にデー
タを出力するように作成されたプログラム は、プログラム実行時に「 , <!
」
とすることにより、画面の代わりにファイル <!
にデータを出力することが出来る。このよ
うな方法を出力のリダイレクションと呼ぶ。入力のリダイレクションと出力のリダイレクションは
「 + "<!
, <!
」のように同時に行うことも出来る。このような入出力のリダ
イレクションを用いることにより、単純なファイル入出力は "./ を用いなくても実現できる。
さらに、標準出力にデータを出力するプログラム と標準入力からデータを入力するプログ
ラム $ に対して、「 P $」のように実行すると、 から標準出力に出力
されるデータを $ で標準入力から読み込むことが出来る。このような方法をパイプ接続と呼
ぶ。このパイプ接続機能は、プログラムを組み合わせて使う機能を提供するものであり有益であ
る。例えば、カレントディレクトリにあるファイルの数を求めたいときに、カレントディレクトリ
内のファイル名を標準出力に出力する「!」コマンド(プログラム)と、標準入力から入力された
テキストデータの行数を出力する「 !」コマンド(プログラム)をパイプで接続し「! P !」のように実行することによりカレントディレクトリ内のファイル数を出力することが出来る。