C言語によるCSVファイルの読み込み方法

396, 2022-01-25

目次

C言語によるCSVファイルの読み込み方法

データをファイルで管理するときによく使われるデータフォーマットがCSVです。
C言語でもこのCSVファイルを読み込むことができます。

CSVのすべての仕様を満たす読み込みは自作するか外部ライブラリを使う必要があります。
しかし簡易的なCSVの読み込みであればC言語の標準ライブラリであるfscanf()を使えば可能です。

この記事ではfscanf()を使ったCSVファイルの読み込み方法を具体的に解説します。

関連記事

そもそもCSVとは?

そもそもCSVとはどんなデータフォーマットなのでしょうか?
CSVは「Comma Separated Value」の頭文字を取っています。
日本語にすると「カンマで区切られた値」という意味になります。

CSVはその名の通り、データをカンマで区切って表現するデータフォーマットです
たとえば「名前、年齢、身長」というデータがあるとして、それをCSVで表現すると↓のようになります。

Taro,30,180.5
Ken,20,190.2
Hanako,25,160.1

↑の場合、1行が1レコード、つまりひと固まりのデータの列になります。
「Taro」が名前で、その隣の「30」が年齢、その隣の「180.5」が身長になります。
それぞれのデータはカンマ(,)で区切られます。

レコードの終端は改行で表現されます。
「Taro」の列の改行までが「Taro」のデータになります。
「Ken」のデータは2件目のレコードになります。

このようにCSVは複数あるデータをレコードの単位で書くことができます。
WindowsのExcelなどにも使われる汎用的なデータフォーマットで世界中で幅広く使われています。

CSVファイルを開く

CSVで書かれたファイルを開くにはファイル処理が必要になります。
CSVファイルはテキストファイルなので開くときはテキストモードでファイルを開きます。

#include <stdio.h>

int main(void) {
    // CSVファイル(data.csv)を開く
    FILE *fin = fopen("data.csv", "rt");
    if (!fin) {
        // 開くのに失敗したらエラーを出力する
        perror("fopen");
        return 1;
    }

    // ここにCSVデータの読み込み処理

    // 使い終わったらファイルを閉じる
    fclose(fin);

    return 0;
}

fopen()関数でファイルを開きますが、fopen()の第1引数にはファイルのパス、第2引数にはオープンモードを指定します。
読み込み用のテキストファイルとして開く場合はモードをrtにします。

fopen()はファイルを開けた場合はファイルポインタ、ファイルの開けなかった場合はNULLを返します。
NULLだった場合はエラー処理になりますが、今回はperror()でエラー内容を出力するだけにとどめています。

ファイルポインタを獲得できたらこのポインタを使って読み込み処理を行います

ファイルポインタは使い終わったらfclose()しておく必要があります。
これをしておかないとファイルが開きっぱなしになったりして色々不具合が出ることもあります。
ファイルは開いたら閉じておきましょう。

CSVデータを読み込む

ファイルポインタを獲得できたら、このファイルポインタを使ってCSVデータを読み込みます
読み込みにはfscanf()を使います。

#include <stdio.h>

// stream → ファイルポインタ
// format → 書式
// ... → 書式への引数
// 返り値 → ファイル終端に達した、またはエラーが発生したらEOF
int fscanf(FILE *stream, const char *format, ...);

読み込むCSVファイルは↓のような内容です。
レコードは左から「名前、年齢、身長」になっています。

Taro,30,180.5
Ken,20,190.2
Hanako,25,160.1

CSVファイルのデータは複数行あるわけなので、これをfscanf()で1行ずつ読み込みます。
fscanf()と合わせてループ文もいっしょに使います。

#include <stdio.h>

int main(void) {
    // CSVファイル(data.csv)を開く
    FILE *fin = fopen("data.csv", "rt");
    if (!fin) {
        // 開くのに失敗したらエラーを出力する
        perror("fopen");
        return 1;
    }

    // CSVデータの読み込み
    char name[100];  // 名前
    int age;  // 年齢
    double height;  // 身長

    // ループで一行ずつ読み込む
    for (; fscanf(fin, "%[^,],%d,%lf\n", name, &age, &height) != EOF; ) {
        printf("name[%s] age[%d] height[%lf]\n", name, age, height);
    }

    // 使い終わったらファイルを閉じる
    fclose(fin);

    return 0;
}

↑のコードの例ではfor文を使って行を読み込んでいます。
fscanf()のところがごちゃごちゃしてますので詳しく見てみたいと思います。

fscanf(fin, "%[^,],%d,%lf\n", name, &age, &height) != EOF

fscanf()第1引数にはファイルポインタを渡します。
第2引数には書式を渡します。
第3引数以降には書式への引数を渡します。
第2引数の書式に従ってファイルポインタからデータが読み込まれ、そのデータがnameageなどの変数に保存されるという流れになります。
配列以外の変数はポインタを渡す必要があります。

カンマ区切りのレコードを読み込みたい場合は、書式をカンマで指定します。
CSVデータの並びは左から「名前、年齢、身長」になっています。
つまり書式は↓のようになるわけです。

"名前,年齢,身長\n"

名前のところは「%[^,]」という指定子を指定します。
これは「カンマ以外の文字を読み取る」という指定です。
角カッコの中にカンマを書き、その頭に否定を意味する「^」を置くと、このような指定になります。
ちなみに%sにするとカンマも文字として読み込んでしまうためうまくいきません。
ですのでこの指定方法を使ってください。

年齢のところは「%d」という指定子にします。
これは変数ageがint型のためです。
年齢は実数になることはないのでこのようにint型にしています。

身長のところは「%lf」にします。
これは実数を読み取る指定子で、身長は実数も許可しているのでこのような指定になります。

身長のあとには改行「\n」を入れておきます。
こうすると改行までfscanf()が読んでくれます。

printf()では読み込んだデータを出力しています。

    printf("name[%s] age[%d] height[%lf]\n", name, age, height);

fscanf()はファイルポインタがファイル終端(EOF)に達した場合は定数EOFを返します。
これが返ってこない間は1行ずつ読み取ることになります。

上記のプログラムを実行すると↓の結果になります。

name[Taro] age[30] height[180.500000]
name[Ken] age[20] height[190.200000]
name[Hanako] age[25] height[160.100000]

おわりに

今回はC言語でCSVファイルを読み込む方法を解説しました。
CSVは汎用的なデータフォーマットでどこにでもその顔を出没させています。
扱えるようになっておくと何かとはかどるでしょう。

(^ _ ^)

CSVでデータを表現する

(・ v ・)

仕事では外部ライブラリ使おうね



この記事のアンケートを送信する