C言語ケーススタディ Excelで作ったデータ(CSVファイル)の読み込みプログラム1




2014年10月より個人の方を対象に、Study C無料提供を開始しました。
C言語を勉強中の方は、学習・教育に最適なC言語インタープリタのStudy Cを使ってみてください(個人の方は無料です)。
大学・高専・高校などの教育機関での採用実績も多数あるロングセラー商品Study Cが、個人向けに無料提供を始めました。
インタープリタの手軽さに加え、ゲームや3Dタートルグラフィックで楽しく勉強したりと、C言語の学習を強力にサポートします。
ブロック崩しゲーム 3Dツリー クリスマスツリー
また、このようなボタンの用意されているページでは、掲載しているプログラムをStudy Cに直接ロードし実行したりすることができます。
Study Cにロードする Study Cにロードし編集する Study Cにロードし実行する
Study C無料利用についての詳細は、このページを参照してください。



Excelなど多くのプログラムではCSV形式(カンマ区切り形式)で内容を出力することができます。 CSVで出力したファイルを自分で加工したりするようなケースは結構あるものです。 今回はCSVファイルの読み込むだけのプログラムを作成します。
Excelで1行目に1、2、3、2行目に11、12、13、3行目に21、22、23と入力してCSV形式でセーブしたのが下記のデータです。
1,2,3
11,12,13
21,22,23
最初にCSVファイルからデータを読み込みます。読み込みにはfgets関数を使用します。 読み込んだデータの最後の文字が改行文字('\n')かどうか調べ改行文字でない場合はエラーとします。 つまり、一行が1024文字以上の場合は取り扱えないデータとしてエラーで処理中断します。 ただファイルの最後の行で改行がない場合はエラーとしないのでfeof関数を使用してファイルの終わりを検出しています。 また、ファイル名はコマンドラインから取得します。
#include <stdio.h>

#define MAX_LINE_SIZE   1024

void    main(int argc, char *argv[])
{
        FILE    *fp;
        char    buff[1024], *wp;
        int     len;

        if(argc != 2){
                printf("コマンドの入力形式が間違っています.\n");
                return;
        }

        fp = fopen(argv[1], "r");
        if(fp == NULL){
                printf("ファイルがオープンできません[%s].\n", argv[1]);
                return;
        }
        for(;;){
                if(fgets(buff, MAX_LINE_SIZE, fp) == NULL)
                        break;
                len = strlen(buff);
                if(len == 0 || buff[len-1] != '\n'){
                        if(feof(fp) == 0){
                                printf("データが不正です[%s].\n", buff);
                                return;
                        }
                }
                buff[len-1] = '\0';
                wp = buff;

                printf(">>>%s\n", wp);
        }
        fclose(fp);
}
Study Cにロードする Study Cにロードし編集する ブラウザとの連携機能が使用可能なStudy Cのバージョンなどについて... 「run csvdata.csv」のように実行する必要があるので実行ボタンはありません
上記のプログラムをコマンドラインから"run ファイル名"の形式で実行すると指定したファイルの内容を表示します。
次に読み込んだ文字列からCSVデータを取り出すGetCSVItem関数を作成します。 この関数はデータを1個づつ取得し、取得後の次から評価すべき文字列のポインタを返します。 つまり想定されるアイテムの数だけGetCSVItem関数を並べ、返された値(ポインタ)を次に呼び出すGetCSVItem関数に渡していけば良いわけです(取得に失敗した場合はNULLを返します)。 今回は1行に3個の項目が存在することを想定して作成しています。
#include <stdio.h>

#define MAX_ITEM_SIZE   100
#define MAX_LINE_SIZE   1024

char    *GetCSVItem(char *wp, char *buff, int size);

void    main(int argc, char *argv[])
{
        FILE    *fp;
        char    buff[MAX_LINE_SIZE], *wp, item[3][MAX_ITEM_SIZE];
        int     i1, len;

        if(argc != 2){
                printf("コマンドの入力形式が間違っています.\n");
                return;
        }

        fp = fopen(argv[1], "r");
        if(fp == NULL){
                printf("ファイルがオープンできません[%s].\n", argv[1]);
                return;
        }
        for(;;){
                if(fgets(buff, MAX_LINE_SIZE, fp) == NULL)
                        break;
                len = strlen(buff);
                if(len == 0 || buff[len-1] != '\n'){
                        if(feof(fp) == 0){
                                printf("データが不正です[%s].\n", buff);
                                return;
                        }
                }
                buff[len-1] = '\0';
                wp = buff;

                if((wp = GetCSVItem(wp, item[0], MAX_ITEM_SIZE)) == NULL){
                        printf("エラー(1)\n");
                        break;
                }
                if((wp = GetCSVItem(wp, item[1], MAX_ITEM_SIZE)) == NULL){
                        printf("エラー(2)\n");
                        break;
                }
                if((wp = GetCSVItem(wp, item[2], MAX_ITEM_SIZE)) == NULL){
                        printf("エラー(3)\n");
                        break;
                }
                if(*wp != '\0'){
                        printf("エラー(4)\n");
                        break;
                }
                for(i1 = 0; i1 < 3; i1++){
                        printf("%d:%s\n", i1+1, item[i1]);
                }
        }
        fclose(fp);
}


char    *GetCSVItem(char *wp, char *buff, int size)
{
        int     i1;

        buff[0] = '\0';
        while(*wp == ' ' || *wp == '\t')
                wp++;
        if(*wp == '\0'){
                return(NULL);
        }
        for(i1 = 0; i1 < MAX_ITEM_SIZE; i1++, wp++){
                if(i1 >= size)
                        return(NULL);
                buff[i1] = *wp;
                if(*wp == '\0'){
                        buff[i1] = '\0';
                        return(wp);
                }
                if(*wp == ','){
                        wp++;
                        buff[i1] = '\0';
                        break;
                }
        }
        return(wp);
}
Study Cにロードする Study Cにロードし編集する ブラウザとの連携機能が使用可能なStudy Cのバージョンなどについて... 「run csvdata.csv」のように実行する必要があるので実行ボタンはありません
上記のプログラムを実行するとCSVの内容を読み込みます。ただし読み込んだ結果は単に表示しているだけです。
CSV形式では"..."といった形式が含まれる場合があります。次回はこのような形式にも対応できるように改造します。


[an error occurred while processing this directive]