こんにちは､ そしてお帰りなさい｡
この講義では､ ファイルからテキストを読み取る方法についてお話したいと思います｡
とりあえず､ テキストファイルの読み取りに専念します｡
そこで､ テキストファイルから文字を読み取る場合､ いくつかの関数を使うことになります｡
最初はfgetcになります｡
読み出し用にオープンされているテキストファイルから文字を読み出します｡
リネームや削除など､ ファイルを開くことができない場合を除いて､
ファイルに対して何らかの操作を行うには､ 必ずファイルを開く必要があることを覚えておいてください｡
しかし､ 読み書きをしたり､ 追記をしたりする場合は､ そのファイルを開かなければならない｡
私たちは､ さまざまなモードでファイルを開くことができることを知っています｡
この場合､ 読み込みのためには､ rまたはrプラスで開いて､ それからfgetcを呼び出すようにします｡
fgetc関数はファイルポインタを唯一の引数とし､
読み取った文字をint型として返します｡
ここでは例として､ int型のmcharを作成し､ fgetc pfileとします｡
pfileをファイルポインタとして､ mchar変数に文字を読み込もうとしているのです｡
pfileが既にオープンされていると考え､ ファイルポインタを戻す｡
mcharはin型です｡ なぜなら､ eofはファイルの終端を表す特殊文字で､
ファイルの終端に達した場合に返されるからです｡
だから､ その整数がeofかどうか､ いつでもチェックできるのです｡
そして､ もしそうなら､ もう読みたくないし､
もうfgetcを呼びたくない｡
fgetcと同等の機能を持つ関数fgetcも用意されています｡
つまりgetcはfgetcとほとんど同じで､ fgetcを使いたいだけなんですね｡
もう少し保護機能が入っていると思います｡
getcでは､ file star型の引数を要求し､ int型として文字redを返し､
返す｡
fgetcとほぼ同じです｡
両者の違いは､ getcがマクロとして実装される可能性があるということだけで､
今はマクロが何なのかさえ分かっていません｡
そこで､ 文字を読み取る関数としてfgetcを使うことにこだわります｡
ファイルの中身を読むことができます｡
ここでも､ 必要に応じて､ ファイルポインターで指定されたファイルをファイルの先頭に位置づける､
この巻き戻し機能を使うことができます｡
だから､ もう一度読みたいときは巻き戻しを使えばいいんです｡
巻き戻し､ そしてファイルポインタと言うだけで､ かなり基本的なことです｡
そこで､ 一例をご紹介します｡
ファイル操作をするときは必ず標準のioヘッダを入れなければならない｡
メイン関数では､ ファイルポインタを作成します｡
これをnullに初期化して､ 整数を作る場合｡
まず最初に､ fオープンコールを使ってファイルを開き､
ファイル名を指定して､ 読み込み用であることを指定します｡
これで､ ファイルポインタが返されます｡
これで､ fpポインタは有効なファイルを指していることになります｡
ファイルを開くことができなかった場合｡ txtが正しいパスでない場合などは､
nullを返すことになります｡
そこで､ NULLをチェックするために､ fpがNULLでないことを確認したいのです｡
nullの場合は､ プログラムを終了します｡
そうでないと､ 普段文字を読むときに､ ループの中に入っていることになります｡
つまり､ ここでは while c equals fgetc fp と言っていますが､ これはファイルから文字を読み､
ファイルポインタをfgetcに渡して､ 整数を返しているのです｡
ファイルの終わりまで読みたくないので､ 返された整数がファイルの終わりであれば､
ループから飛び出すことができることを忘れないでください｡
そうでなければ､ パーセントcとcを使って文字をプリントアウトすればいいのです｡
最後に､ ファイルを閉じて､ ファイルポインタをnullに設定し､
戻ることができます｡
これを利用して､ コードブロックの中に作ってみましょう｡
以下は､ コードブロック内のプログラムです｡
このプログラムは､ プログラムが動作している場所のディスク上にファイルがないと動作しませんよ､
ということです｡
まず､ これをビルドすると､ ハードディスクのどこかに実行ファイルが作成されるはずです｡
私は自分のプロジェクトをすべてドットローンのディレクトリの中に入れています｡
ダウンロード・ディレクトリに移動して､ プロジェクト名（これは単なるテスト・プロジェクトなので､
プロジェクトを保存している場所がどこであれ､ 私の場合はtestにあります）に移動します｡
testに行くと､ binディレクトリの中に､ debugの中に､ あなたの実行ファイルがあるのがわかると思います｡
ここで､ 親戚がいた場合のファイルを作成します｡
パスですから､ ここで新しいファイルを作れば､ それをテキストファイルとして持つことができますので､
テキスト文書として作成し､ ファイル名を付けなければなりません｡
そして､ その中に情報を入れていく｡
ハイこれがジェイソンのラインフィードですというようなデータを入れるだけです｡
よし､ ダメだ､ そうだ､ 保存しておこう｡
このプログラムが動作するためには､ このファイルが存在する必要があります｡
そこで､ ファイルを作成しました｡
これで､ 実行すると､ 今追加したものを読み取ってプリントアウトしてくれることを期待します｡
error and file opening file no such file directoryと表示されるのですが､
デバッグフォルダに置いているからでしょうか｡
しかも､ これはデバッグで動いているわけではありません｡
では､ デバッグで実行してみましょう､ 今なら多分うまくいくと思います｡
デバッグ､ スタートと言えばいいのです｡
これはうまくいけばデバッグディレクトリに実行ファイルを探すことになります｡
確実に実行させたい｡
まだないので､ 実行ファイルがどこにあるか確認する必要があります｡
他の場所で試してみるか､ いっそのことデバッグディレクトリの中で実行ファイルを実行すれば､
そこにあるはずです｡
だから､ ここをダブルクリックしても､ 実際には......ポーズがかからないんです｡
飛び出すのです｡
そこで､ リターンではなく､ システムポーズと言えば､
実行するまでプログラムを終了させないことができます｡
では､ 次に試してみましょう｡
そのため､ 現在は一時停止しており､ プログラムは実行されていません｡
そして､ あなたが見たのは､ 「こんにちは､ ジェイソンです」というものでした｡
ファイルを見つけることができ､ OKをプリントアウトし､ NGをプリントアウトした後､
一時停止した｡
そうしないと､ プログラムを実行したときに､ データを高速にプリントして､
プログラムを終了してしまうからです｡
それでテストができるわけです｡
実行ファイルがどこから実行されているのかが格納されている必要があります｡
プロジェクトディレクトリのどこか他の場所から実行されているはずです｡
どこから走っているのかよくわからない｡
ソースコードのある場所にファイルを移動してみるのもいいかもしれませんね｡
ここから実行しているのかもしれません｡
だからここに､ それを入れる｡
そして､ 今度はIDから実行してみると､ もしかしたらうまくいくかもしれません｡
私たちは作らない｡
走らせたら､ 見つけることができたんです｡
だから､ ソースコードがある場所の中にファイルを置かなければならないようだ｡
だから､ そのファイルファイルを置きさえすればいい｡ のテキストをプロジェクトファイル内で確認することができます｡
このように､ ファイルを開いて1文字を読み取る方法を簡単に紹介しましたが､
通常､ 文字列を読み取ることが多いため､ ファイルから読み取る最も効率的な方法とは言えません｡
でも､ これなら開けられる｡
fのオープンコールを見て､ whileループに気づきましたね｡
それが大事なんです｡
ここでもう一度､ ファイルから文字列を読み込む方法について説明しましょう｡
これは､ より効率的です｡
それが一文字の読み方なんですね｡
文字列の読み取りはどうでしょうか？
fgets関数を使って､ 任意のファイルやストリームから読み込むことができます｡
これは､ 文字列を読み取るものです｡
第1引数に文字列を取る｡
読み出したい文字数､ そして実際のファイルポインタを指定します｡
つまり､ この関数はstrが指すメモリ領域にある文字列を読み込もうとしているわけです｡
そのため､ 実際にデータが格納されるバッファを渡す必要があります｡
しかもそれはポインターなので､ メモリを確保する必要があります｡
そして､ 第3パラメータとして指定されたファイルポインタから読み込むことになります｡
そして､ ncharは､ どれだけのデータを読み込むかを示すことになる｡
つまり､ ncharsを10とすると､ 最初に改行がない限り､ 10文字を読み込むことになるのです｡
つまり､ 行全体を読むか､ 第2パラメータで指定した文字数を読むかのどちらかになるわけです｡
行末はバックスラッシュnのどちらか先に発生したほうで指定する｡
改行文字が赤の場合は､ 文字列に保持され､
文字列の末尾にヌル末尾が付加される｡
ですから､ 実際にそれ以上の文字を指定すると､ 改行まで読んでから飛び出して､
その改行文字を取得して､ その末尾にヌル文字を置くということになります｡
エラーがなければ､ fgetsは最初のパラメータであるポインタを返そうとします｡
関数から返されるポインタを返すことになります｡
そして､ 最初のパラメータとしてstrポインタを投入することになります｡
エラーが発生した場合はnullを返す｡
そして､ ファイルの最後を読むとnullが返される､ つまり､ 文字列をすべて読んだことになるのです｡
では､ 例を見てみましょう｡
ここでは､ メインとなる､ 文字列を作成するファイルポインタを作成しています｡
これはポインターで､ データのマロケーションは行わず､ 単に文字配列を作成しただけです｡
rなので読むだけのファイルを開いています｡
ヌルなら飛び出せということです｡
そうでなければ､ fgetsと言うだけで､ 60文字で読み込んでいます｡
あるいは､ その前に改行があれば､ 改行して､ その後にstrバッファにあるものをプリントアウトします｡
つまり､ strは最初に渡される文字なのです｡
そして､ ファイルポインタを閉じてNULLをセットし､ 0を返します｡
では､ もう一度､ コードブロックIDEの中で見てみましょう｡
このプログラムで変わったのは､ 本当に14行目から17行目までだけです｡
fgetsを使って文字列を読み込んで､ strバッファを用意しています｡
ここで文字配列を作成する必要があります｡
これはstrで､ 60個を含むようにします｡
60で読んでいます｡
改行を加えるので､ 59で読み込んで､ その最後に改行を加えることになります｡
だから､ 61と言えるのです｡
そして､ fgetsはif文の中で､ 60文字に達するか改行されるまで各文字列を読み込んで､
その文字列をプリントアウトすることにしています｡
whileループではないので､ ファイルの終わりまで読んでいないことにお気づきでしょう｡
ファイルの終端を読み込むと､ NULLが表示される｡
ですから､ もしこれを作るなら､ 見積もりは正しく行いたいものです｡
パワーポイントからコピーすると､ いつも引用がめちゃくちゃになる｡
そして､ 変数cが使用されていないことを確認したい......大丈夫です｡
では､ これを実行してみましょう｡
そして､ ご覧の通りジェイソンです｡
そこで､ 実際にファイルからテキストを一行まるごと読み込んでみましょう｡
一行目に書いてあった｡
そこで､ もう一度呼び出して､ 2行目で読むことになる｡
読み込むバイト数を変更した場合､ 例えば10だけ読みたいとすると､
行全体を読み込むのではなく､ 10だけ読み込んで､ その10を返します｡
だから､ ここで私たちはちょうどそれを持っているハイこのI.
つまり､ 2番目のパラメータの文字数か､
改行されるまでの文字数を読み込んで､ それをstrに格納するわけです｡
Str は文字配列である｡
それをプリントアウトするのがfgetsです｡
Fgetsは読み出しの効率が良いですね｡
文字と一度に読み込まないから､ より多くのデータを読み込むことができるのです｡
一度に一文字ずつ読むのは効率が悪い｡
これで､ 1文字単位で読み込む方法がわかったので､
改行や文字数を読み込むまでの文字列の読み方もわかった｡
しかし､ ファイルからフォーマットされた入力を読み込むことも可能です｡
そこで､ getc, fgetc, fgetsを用意しました｡
そして､ 今度はfscanfという別の関数があります｡
これはフォーマットされた入力です｡
フォーマット入力とは､ デリミタがある､ あるいは特定のフォーマットが関連付けられているようなデータである｡
このfscanf関数は､ streamからファイルを受け取り､ 次にformatを受け取ります｡
書式は､ あなたが使っているprintfの書式指定子と同じです｡
だから､ 整数や倍数で読みたい場合は､ 倍数で紹介されているファイル内のデータを指定すれば､ scanfと同じように空白文字が見えるまでそれを読み込んでくれるのだ｡
そこで､ fscanf関数の第1引数には､ ストリームを識別するファイルオブジェクトへのポインタを指定します｡
どのファイルから読み込んでいるのかを知る必要があります｡
この関数の第2引数はフォーマットである｡
を 1 つ以上含む c 文字列である｡
空白文字､ 非空白文字､ フォーマット指定子｡
使い方はscanfとprintfの中のtheと同じですが､ その代わりにファイルからです｡
二重引用符の内側には､ テキストや空白文字､ 非空白文字を入れることができますが､
フォーマット指定子は､ データをどのように読み込むかを示すものです｡
そして､ それを読み込むための変数を指定するのです｡
そこで､ この関数は､ 入力項目のマッチングと割り当てに成功した数を返す｡
というわけで､ こんな感じです｡
mainがstr1, str2, str3という3つの文字配列を､ それぞれ10バイトだけ作成していることがわかると思います｡
yearという整数を作り､ ファイルポインタを打ち込む｡
まず最初にすることは､ ファイルを開くことです｡
今回は､ 読み書きのために開放しているのです｡
しかし､ 実際には何も書き込まず､ そこから読み取ったものを表示するだけです｡
ファイルポインタがNULLでないことを確認する｡
そして､ ここでは､ 実際にfputsというファイルに何かを入れています｡
まだその話はしていないのですが､ これは何かを書いているんです｡
ここでは､ fscanfにフォーカスします｡
fscanfは､ フォーマットされたデータを読み込もうとしています｡
そして､ スペースで区切られた3つの文字列を読み込むのです｡
そして､ パーセントをスペースパーセントとして､ スペースパーセントsスペースパーセントdと表示されるわけです｡
それから､ 3文字配列のどこに読み込むかと言うことですが､
年号にはアドレス演算子を指定しなければなりません｡
しかし､ データは書き込むときに特定の書式になります｡
そして､ フォーマットされたものを読み込むときは､ そのファイルがどのように書かれているのか､
フォーマットを理解しなければなりません｡
ここでは､ 文字列を空白で区切ってファイルを書き込むことがわかる｡
そうやって読み込んでいくわけです｡
それで､ fscanfを1回呼び出すだけで読み込むことができるのです｡
私たちのフォームを第2引数に指定子として使用し､ その後､ 各カンマの別ごとに可変数の引数を使用して､
それを読み込むデータを指定することができるのです｡
そして､ そのデータ､ 年の3つの文字列をプリントアウトして､
再びファイルを閉じます｡
以上､ 3つの方法でファイルからデータを読み込むことができます｡
文字で読むことも､ 文字列で読むことも､ フォーマットされたデータを読むこともできます｡
そして､ その整形方法はscanfと非常に似ていることにお気づきでしょう｡
フォーマット指定子､ 読み込むための変数を使用するのです｡
これをより身近に感じることができるデータの読み方にチャレンジしていただきます｡
かなり基本的なことなのですが
オープンコールを行い､ ファイルポインタを使い､
この3つの関数を使うのです｡
ありがとうございます｡