トップC-Tips > 簡単な CSVファイルの読み込み
簡単な CSVファイルの読み込み

1.はじめに

ここでは簡単な数値だけの CSVファイルの読み込みプログラムを示す。 数値は、3桁毎にカンマをいれるようなものでなく、数字だけの整数とする。

一般的な CSVファイルは要素にカンマや引用符、漢字などが含まれるため、 その読み込みプログラムは簡単ではない。

2.準備

ここでは、0から255までの1バイトで表される数値を対象とする。 最初に、乱数を用いて、テストデータを作る。

プログラムおよび実行結果を以下に示す。20列x200行の test.csv ファイルが生成された。

#include <stdio.h>

int main() {
    FILE *fp = fopen("test.csv", "w");
    for (int i = 0; i < 200; i++) {
        for (int j = 0; j < 20; j++) {
            fprintf(fp, "%d%c", rand() % 256, j < 19 ? ',' : '\n');
        }
    }
    fclose(fp);
}

[test.csv]
41,35,190,132,225,108,214,174,82,144,73,241,241,187,233,235,179,166,219,60
135,12,62,153,36,94,13,28,6,183,71,222,179,18,77,200,67,187,139,166
 [中略]
214,186,227,28,198,123,52,177,176,0,25,230,162,178,166,144,240,38,113,254

3.CSVファイル読み込みプログラム

上で作成した test.csv ファイルを unsigned char data[200][20]; に読み込むプログラムを作成する。 この場合、1行の長さは最大で 80バイトである。 一行を十分に読み込めるバッファを用意し、行単位で読み込み処理を行う。

プログラムを下に示す。数値に誤りがないことが分かっているならば、 num の値のチェックは省いてもよい。

#include <stdio.h>

int main() {
    char buf[1000], *p, *end;
    unsigned char data[200][20];

    FILE *fp = fopen("test.csv", "r");
    for (int i = 0; i < 200; i++) {
        if (fgets(buf, sizeof(buf), fp) == NULL) {  // 一行読み込み。改行コードも含まれる。
            break;  // 読込終了
        }
        p = buf;
        for (int j = 0; j < 20; j++) {
            long num = strtol(p, &end, 10);         // 10進数を読み取る
            if (p == end) break;                    // 読み取り終了
            if (num < 0 || num > 255) {
                fprintf(stderr, "not 0 〜 255: i=%d, j=%d, num=%d\n", i, j, num);
                fclose(fp);
                return 1;   // 異常終了
            }
            data[i][j] = num;
            p = end + 1;    // ',' をスキップする
        }
    }
    fclose(fp);

    // 読込結果の確認
    for (int i = 0; i < 200; i++) {
        for (int j = 0; j < 20; j++) {
            printf("%d%c", data[i][j], j < 19 ? ',' : '\n');
        }
    }
    return 0;   // 正常終了
}

今回のように、行数、列数が予め分かっているならば、エラーチェックも省いて 次のようにしてもよい。

一般には適宜エラーチェックを入れることになるため、プログラムがその分読みづらくなる。

#include <stdio.h>

int main() {
    char buf[1000], *p, *end;
    unsigned char data[200][20];

    FILE *fp = fopen("test.csv", "r");
    for (int i = 0; i < 200; i++) {
        fgets(buf, sizeof(buf), fp);
        p = buf;
        for (int j = 0; j < 20; j++) {
            data[i][j] = strtol(p, &end, 10);         // 10進数を読み取る
            p = end + 1;    // ',' をスキップする
        }
    }
    fclose(fp);

    // 読込結果の確認
    for (int i = 0; i < 200; i++) {
        for (int j = 0; j < 20; j++) {
            printf("%d%c", data[i][j], j < 19 ? ',' : '\n');
        }
    }
}