MMGamesロゴ  MMGames
Twitterシェアボタン  Facebookシェアボタン   
しんで覚えるC言語
しんで覚えるC言語

テキストファイルの読み書き

ファイルの取り扱い
今までは、入出力を行う場合、すべて画面に表示してきました。
画面に表示すれば、結果がすぐにわかって便利だからです。
しかし、画面に表示された結果は、プログラムが終わると消えてしまいます。
また、膨大な量のデータを画面に表示するのは現実的ではありません。

この様な場合、ファイルにデータを保存するのが普通です。
ファイルとして保存されたデータは、ディスク上に保存されるので、
消えることはなく、コピーや再編集が容易です。

ここでは、C言語でファイルを読み書きする方法を説明します。
ファイルの開閉
プログラムからファイルを操作する手順は、おおむね次のような順番で行われます。

ファイルを操作する手順
ファイルを開く -> ファイルに読み書きする -> ファイルを閉じる

つまり、ファイル操作には、ファイルの開閉が必須となっています。
そこで、C言語には、ファイルを開閉する関数が用意されています。
開く関数が fopen関数、閉じる関数が fclose関数です。
この関数を使うには、stdio.h のインクルードが必要になります。
それぞれの関数の使い方は、次の通りになります。

ファイルを開閉する関数
FILE型のポインタ変数 = fopen(ファイル名, モード);
fclose(FILE型のポインタ変数);

ファイル名とは、その名の通りのファイル名です。
フルパスで指定することも、名前だけで指定することもできます。

モードとは、ファイルを開く目的を表す文字列のことです。
モードには、次の6種類の文字列の内どれか1つを指定します。

モード文字列 目的
r 読み込み。ファイルがない時は失敗。
r+ 読み書き。ファイルがない時は失敗。
w 書き込み。ファイルがあっても空のファイルを作る。
w+ 読み書き。ファイルがあっても空のファイルを作る。
a 追加書き込み。ファイルがない時は作る。
a+ 追加読み書き。ファイルがない時は作る。

FILE型は今までに出てきたことがない新しい型ですが、その正体は構造体です。
fopen関数を実行すると、ファイル情報を持つFILE型へのポインタが返されます。
このポインタは、以後、開いたファイルの識別子として使うだけなので、
ポインタ特有の操作を行ったり、構造体の要素を使うことはありません。
慣習的に、FILE型へのポインタ変数を、ファイルポインタと呼びます。

ここまで説明したことがわかれば、ファイルの開閉ができます。
次のプログラムは、test.txtと言う名前のファイルを書き込みのために開く例です。

ソースコード
#include <stdio.h>

int main(void)
{
    FILE *file;
    file = fopen("test.txt", "w");
    fclose(file);
    return 0;
}

このプログラムを実行すると、test.txtという名前のファイルが作成されます。
今回は開いただけなので、当然中身は空っぽです。

fcloseの役割
今回のプログラムだけだと、fclose関数はとくに必要ないように見えてしまいます。
しかし、fclose関数には重要な役割がありますので、忘れてはいけません。

現代のパソコンでは、同時に複数のアプリが動作できます。
もし、同じファイルを同時に別々のアプリで書き換えてしまうと、
どちらを反映すれば良いのかわからなくなってしまいます。

そこで、fopen関数で書き込みができるように開いたファイルには、
他のソフトで書き換えられないよう、ロックしています。
fclose関数はロックを解除して、他のアプリから使えるようにするために必要です。

ファイルへの書き込み
ファイルへテキストを書き込む関数は、多くの種類が用意されています。
その中に、馴染みのprintf関数と良く似た、fprintf関数があります。
fprintf関数の使い方は、次の通りです。

fprintf関数
fprintf(ファイルポインタ, 書き込み文字列, 変数・・・);

使い方は、ファイルポインタを指定すること以外、printf関数とまったく同じですが、
指定した文字列は、画面ではなくファイルに書き込まれます。
次のプログラムは、test.txtファイルに Hello,world の文字列を書き込みます。

ソースコード
#include <stdio.h>

int main(void)
{
    FILE *file;
    file = fopen("test.txt", "w");
    fprintf(file, "Hello,world");
    fclose(file);
    return 0;
}

このプログラムを実行すると、test.txtファイルの中身は次のようになります。
test.txtファイルは、実行ファイルと同じフォルダに作られます。

実行後の「test.txt」
Hello,world

printf関数と同じように、変数の値を書き込むこともできます。
次のプログラムは、test.txtファイルに変数iの値を書き込みます。

ソースコード
#include <stdio.h>

int main(void)
{
    int i = 100;
    FILE *file;
    file = fopen("test.txt", "w");
    fprintf(file, "%d", i);
    fclose(file);
    return 0;
}

このプログラムを実行すると、test.txtファイルの中身は次のようになります。

実行後の「test.txt」
100


読み込みと追加の場合
読み込みモードで開いた場合、書き込み用の関数を使っても何も起きません。
追加モードで開いた場合、元のファイルの最後にデータが追加されます。

ファイルからの読み込み
ファイルのテキストを読み込む関数にも多くの種類がありますが、
馴染みのscanf関数に似たfscanf関数があります。
先頭でファイルポインタを指定することを除き使い方はscanf関数と同じです。

scanf関数はキーボートから読み込むため、実行すると入力待ちになりましたが、
fscanf関数では、ファイルのテキストを先頭から読み込みます。
次のプログラムは、test.txtファイルから先頭の数字を読み込んで表示します。

ソースコード
#include <stdio.h>

int main(void)
{
    int i;
    FILE *file;
    file = fopen("test.txt", "r");
    fscanf(file, "%d", &i);
    fclose(file);
    printf("%d\n", i);
    return 0;
}

このプログラムの実行結果は、test.txtファイルの中身によって異なります。
test.txtファイルの中身が次の通りだった場合、実行結果は次の通りになります。

実行前の「test.txt」ファイルの中身
100


実行結果
100

上の例のように%d指定子を使用した場合、数字以外のテキストは無視されます。
test.txtファイルの中身が次の通りだった場合、実行結果は次の通りになります。

実行前の「test.txt」ファイルの中身
test100


実行結果
100

文字列の入力に使用する%s指定子を使用すれば文字列全体を読み込めます。
しかし、スペースなどが含まれる場合にはそこまでしか読み込まれません。

実行前の「test.txt」ファイルの中身
test100


実行結果
test100

また、複数の数値をカンマ(,)で区切って並べてやれば、
複数の変数を読み込むことも可能です。

ソースコード
#include <stdio.h>

int main(void)
{
    int i, j;
    FILE *file;
    file = fopen("test.txt", "r");
    fscanf(file, "%d,%d", &i, &j);
    fclose(file);
    printf("i = %d : j = %d\n", i, j);
    return 0;
}


実行前の「test.txt」ファイルの中身
23,56


実行結果
i=23 : j=56

この様にカンマ(,)で区切って数値や文字列を並べたファイルをCSV形式と呼びます。
エクセルなどの表計算ソフトで扱える汎用的なファイル形式として知られています。
上記のプログラムによって、エクセルで保存したCSVファイルを、自作プログラムで読み込むことも可能です。
エクセルで保存したCSVは複雑になりがちなのでそれほど簡単ではありませんが・・・


本サイトについて

苦しんで覚えるC言語(苦C)は
C言語入門サイトの決定版です。
C言語の基本機能を体系立てて解説しており、
市販書籍と同等以上の完成度です。

第0部:プログラム概要編
  1. プログラムとは何か?
2章:プログラムの書き方
  1. 書き方のルール
  2. 書き方の慣習
  3. 練習問題2
3章:画面への表示
  1. 文字列の表示
  2. 改行文字
  3. 練習問題3
6章:キーボードからの入力
  1. 入力用の関数
  2. 入力の恐怖
  3. 練習問題6
9章:回数が決まっている繰り返し
  1. 繰り返しを行う文
  2. ループ動作の仕組み
  3. 練習問題9
10章:回数がわからない繰り返し
  1. 回数不明ループ
  2. 入力チェック
  3. 練習問題10
13章:複数の変数を一括して扱う
  1. 複数の変数をまとめて扱う
  2. 配列の使い方
  3. 練習問題13
20章:複数のソースファイル
  1. 最小限の分割
  2. 分割の定石
  3. 練習問題20

コメント
COMMENT

💬 コメント投稿欄を開く