[C言語] CSVを読み込んで2行目からデータを取得する方法を解説

C言語でCSVファイルを読み込み、2行目以降のデータを取得する方法について解説します。

まず、ファイルを開くためにfopen関数を使用し、読み込みモードでファイルを開きます。

次に、fgets関数を用いて1行目をスキップし、2行目以降のデータを取得します。

取得したデータは、strtok関数を使ってカンマ区切りで分割し、各要素を処理します。

最後に、ファイルを閉じるためにfclose関数を使用します。

この記事でわかること
  • CSVファイルの基本的な読み込み手順
  • 2行目からデータを取得する方法
  • ファイル操作におけるエラーハンドリングの方法
  • CSVデータを配列や構造体に格納する応用例
  • 大規模なCSVファイルを扱う際の注意点と改善策

目次から探す

CSVファイルの読み込み手順

CSVファイルをC言語で読み込む際には、いくつかの基本的な手順を踏む必要があります。

ここでは、ファイルのオープンからデータの解析までの流れを解説します。

ファイルのオープン方法

CSVファイルを読み込むためには、まずファイルをオープンする必要があります。

C言語では、fopen関数を使用してファイルを開きます。

#include <stdio.h>
int main() {
    // ファイルを読み込みモードで開く
    FILE *file = fopen("data.csv", "r");
    if (file == NULL) {
        // ファイルが開けなかった場合のエラーメッセージ
        printf("ファイルを開けませんでした。\n");
        return 1;
    }
    // ファイルを閉じる
    fclose(file);
    return 0;
}

このコードでは、data.csvというファイルを読み込みモードで開いています。

ファイルが存在しない場合や開けない場合には、エラーメッセージを表示します。

1行ずつデータを読み込む方法

ファイルを開いた後は、fgets関数を使って1行ずつデータを読み込みます。

#include <stdio.h>
int main() {
    FILE *file = fopen("data.csv", "r");
    if (file == NULL) {
        printf("ファイルを開けませんでした。\n");
        return 1;
    }
    char line[1024]; // 1行分のバッファ
    while (fgets(line, sizeof(line), file)) {
        // 読み込んだ行を表示
        printf("%s", line);
    }
    fclose(file);
    return 0;
}

このコードは、data.csvの内容を1行ずつ読み込み、コンソールに表示します。

fgetsは、ファイルの終わりに達するとNULLを返します。

デリミタ(区切り文字)の処理

CSVファイルでは、カンマ,がデリミタとして使用されます。

strtok関数を使って、行をカンマで分割します。

#include <stdio.h>
#include <string.h>
int main() {
    FILE *file = fopen("data.csv", "r");
    if (file == NULL) {
        printf("ファイルを開けませんでした。\n");
        return 1;
    }
    char line[1024];
    while (fgets(line, sizeof(line), file)) {
        char *token = strtok(line, ",");
        while (token != NULL) {
            // 分割されたトークンを表示
            printf("%s\n", token);
            token = strtok(NULL, ",");
        }
    }
    fclose(file);
    return 0;
}

このコードは、各行をカンマで分割し、各要素を表示します。

文字列の分割と解析

分割された文字列を解析することで、必要なデータを取得できます。

例えば、数値データを取得する場合は、atoiatof関数を使用します。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
    FILE *file = fopen("data.csv", "r");
    if (file == NULL) {
        printf("ファイルを開けませんでした。\n");
        return 1;
    }
    char line[1024];
    while (fgets(line, sizeof(line), file)) {
        char *token = strtok(line, ",");
        while (token != NULL) {
            // 文字列を数値に変換して表示
            int number = atoi(token);
            printf("%d\n", number);
            token = strtok(NULL, ",");
        }
    }
    fclose(file);
    return 0;
}

このコードは、CSVファイルの各要素を整数に変換して表示します。

atoi関数は文字列を整数に変換するために使用されます。

2行目からデータを取得する方法

CSVファイルを読み込む際に、1行目はヘッダー情報として扱われることが多く、2行目以降から実際のデータを取得することが一般的です。

ここでは、1行目をスキップして2行目からデータを取得する方法を解説します。

1行目をスキップする方法

1行目をスキップするためには、最初にfgets関数を1回呼び出して、1行目を読み込んで無視します。

#include <stdio.h>
int main() {
    FILE *file = fopen("data.csv", "r");
    if (file == NULL) {
        printf("ファイルを開けませんでした。\n");
        return 1;
    }
    char line[1024];
    // 1行目を読み込んでスキップ
    fgets(line, sizeof(line), file);
    // ここから2行目以降の処理を行う
    while (fgets(line, sizeof(line), file)) {
        printf("%s", line);
    }
    fclose(file);
    return 0;
}

このコードでは、最初のfgetsで1行目を読み込んでいますが、その内容は使用せずに次の行から処理を開始します。

ループを使った行の読み込み

2行目以降のデータを取得するためには、fgetsを使ってループで行を読み込みます。

ループはファイルの終わりに達するまで続けます。

#include <stdio.h>
int main() {
    FILE *file = fopen("data.csv", "r");
    if (file == NULL) {
        printf("ファイルを開けませんでした。\n");
        return 1;
    }
    char line[1024];
    fgets(line, sizeof(line), file); // 1行目をスキップ
    // 2行目以降を読み込むループ
    while (fgets(line, sizeof(line), file)) {
        printf("%s", line);
    }
    fclose(file);
    return 0;
}

このループでは、fgetsNULLを返すまで、つまりファイルの終わりに達するまで行を読み込み続けます。

2行目以降のデータの処理

2行目以降のデータを処理する際には、前述のデリミタ処理や文字列解析を行います。

以下の例では、2行目以降のデータをカンマで分割し、各要素を表示します。

#include <stdio.h>
#include <string.h>
int main() {
    FILE *file = fopen("data.csv", "r");
    if (file == NULL) {
        printf("ファイルを開けませんでした。\n");
        return 1;
    }
    char line[1024];
    fgets(line, sizeof(line), file); // 1行目をスキップ
    // 2行目以降のデータを処理
    while (fgets(line, sizeof(line), file)) {
        char *token = strtok(line, ",");
        while (token != NULL) {
            printf("%s\n", token);
            token = strtok(NULL, ",");
        }
    }
    fclose(file);
    return 0;
}

このコードは、2行目以降の各行をカンマで分割し、各要素を表示します。

strtok関数を使って、デリミタであるカンマを基に文字列を分割しています。

エラーハンドリング

CSVファイルを読み込む際には、さまざまなエラーが発生する可能性があります。

ここでは、ファイルが存在しない場合や読み込みエラー、データ形式が不正な場合の対処方法について解説します。

ファイルが存在しない場合の対処

ファイルが存在しない場合、fopen関数NULLを返します。

この場合、適切なエラーメッセージを表示し、プログラムを終了させることが重要です。

#include <stdio.h>
int main() {
    FILE *file = fopen("data.csv", "r");
    if (file == NULL) {
        // ファイルが存在しない場合のエラーメッセージ
        printf("エラー: ファイルが見つかりません。\n");
        return 1;
    }
    // ファイルが正常に開けた場合の処理
    fclose(file);
    return 0;
}

このコードは、ファイルが存在しない場合にエラーメッセージを表示し、プログラムを終了します。

読み込みエラーの処理

ファイルの読み込み中にエラーが発生することがあります。

fgets関数NULLを返した場合、エラーが発生した可能性があります。

エラーの原因を特定するために、ferror関数を使用します。

#include <stdio.h>
int main() {
    FILE *file = fopen("data.csv", "r");
    if (file == NULL) {
        printf("エラー: ファイルが見つかりません。\n");
        return 1;
    }
    char line[1024];
    while (fgets(line, sizeof(line), file)) {
        // 読み込んだ行を処理
    }
    if (ferror(file)) {
        // 読み込みエラーが発生した場合の処理
        printf("エラー: ファイルの読み込み中に問題が発生しました。\n");
    }
    fclose(file);
    return 0;
}

このコードは、ファイルの読み込み中にエラーが発生した場合にエラーメッセージを表示します。

データ形式が不正な場合の対応

CSVファイルのデータ形式が不正な場合、プログラムが期待通りに動作しないことがあります。

データ形式のチェックを行い、問題がある場合には適切な処理を行います。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
    FILE *file = fopen("data.csv", "r");
    if (file == NULL) {
        printf("エラー: ファイルが見つかりません。\n");
        return 1;
    }
    char line[1024];
    fgets(line, sizeof(line), file); // 1行目をスキップ
    while (fgets(line, sizeof(line), file)) {
        char *token = strtok(line, ",");
        while (token != NULL) {
            // 文字列を数値に変換
            char *endptr;
            int number = strtol(token, &endptr, 10);
            if (*endptr != '\0' && *endptr != '\n') {
                // データ形式が不正な場合の処理
                printf("エラー: 不正なデータ形式が検出されました: %s\n", token);
            } else {
                printf("%d\n", number);
            }
            token = strtok(NULL, ",");
        }
    }
    fclose(file);
    return 0;
}

このコードは、各トークンを整数に変換し、変換に失敗した場合にはエラーメッセージを表示します。

strtol関数を使用して、変換の成否を確認しています。

応用例

CSVファイルの基本的な読み込み方法を理解したら、次はそのデータを活用する応用例を考えてみましょう。

ここでは、複数行のデータを配列に格納する方法、特定の列のデータを抽出する方法、そしてCSVデータを構造体にマッピングする方法を紹介します。

複数行のデータを配列に格納する

CSVファイルのデータを配列に格納することで、後でデータを簡単に操作することができます。

以下の例では、各行のデータを2次元配列に格納します。

#include <stdio.h>
#include <string.h>
#define MAX_ROWS 100
#define MAX_COLS 10
#define MAX_LINE_LENGTH 1024
int main() {
    FILE *file = fopen("data.csv", "r");
    if (file == NULL) {
        printf("エラー: ファイルが見つかりません。\n");
        return 1;
    }
    char data[MAX_ROWS][MAX_COLS][MAX_LINE_LENGTH];
    char line[MAX_LINE_LENGTH];
    int row = 0;
    fgets(line, sizeof(line), file); // 1行目をスキップ
    while (fgets(line, sizeof(line), file) && row < MAX_ROWS) {
        int col = 0;
        char *token = strtok(line, ",");
        while (token != NULL && col < MAX_COLS) {
            strcpy(data[row][col], token);
            token = strtok(NULL, ",");
            col++;
        }
        row++;
    }
    fclose(file);
    // 配列に格納されたデータを表示
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < MAX_COLS; j++) {
            printf("%s ", data[i][j]);
        }
        printf("\n");
    }
    return 0;
}

このコードは、CSVファイルのデータを2次元配列に格納し、後でそのデータを表示します。

特定の列のデータを抽出する

特定の列のデータを抽出することで、必要な情報だけを効率的に取得できます。

以下の例では、2列目のデータを抽出して表示します。

#include <stdio.h>
#include <string.h>
int main() {
    FILE *file = fopen("data.csv", "r");
    if (file == NULL) {
        printf("エラー: ファイルが見つかりません。\n");
        return 1;
    }
    char line[1024];
    fgets(line, sizeof(line), file); // 1行目をスキップ
    while (fgets(line, sizeof(line), file)) {
        char *token = strtok(line, ",");
        int col = 0;
        while (token != NULL) {
            if (col == 1) { // 2列目のデータを抽出
                printf("%s\n", token);
            }
            token = strtok(NULL, ",");
            col++;
        }
    }
    fclose(file);
    return 0;
}

このコードは、CSVファイルの2列目のデータを抽出して表示します。

CSVデータを構造体にマッピングする

CSVデータを構造体にマッピングすることで、データをより直感的に扱うことができます。

以下の例では、CSVデータを構造体に格納します。

#include <stdio.h>
#include <string.h>
#define MAX_ENTRIES 100
typedef struct {
    char name[50];
    int age;
    float salary;
} Employee;
int main() {
    FILE *file = fopen("data.csv", "r");
    if (file == NULL) {
        printf("エラー: ファイルが見つかりません。\n");
        return 1;
    }
    Employee employees[MAX_ENTRIES];
    char line[1024];
    int index = 0;
    fgets(line, sizeof(line), file); // 1行目をスキップ
    while (fgets(line, sizeof(line), file) && index < MAX_ENTRIES) {
        char *token = strtok(line, ",");
        strcpy(employees[index].name, token);
        token = strtok(NULL, ",");
        employees[index].age = atoi(token);
        token = strtok(NULL, ",");
        employees[index].salary = atof(token);
        index++;
    }
    fclose(file);
    // 構造体に格納されたデータを表示
    for (int i = 0; i < index; i++) {
        printf("名前: %s, 年齢: %d, 給与: %.2f\n", employees[i].name, employees[i].age, employees[i].salary);
    }
    return 0;
}

このコードは、CSVファイルのデータをEmployee構造体に格納し、各エントリを表示します。

構造体を使用することで、データの各フィールドに簡単にアクセスできます。

よくある質問

CSVファイルの読み込み速度を改善するには?

CSVファイルの読み込み速度を改善するためには、以下の方法を検討してください。

  • バッファサイズの調整: fgetsで使用するバッファサイズを大きくすることで、読み込み回数を減らし、速度を向上させることができます。
  • メモリマッピング: 大きなファイルを扱う場合、メモリマッピングを使用することで、ファイルの一部をメモリにマップし、効率的にアクセスできます。
  • 非同期I/O: 非同期I/Oを使用することで、I/O操作と計算を並行して行い、全体の処理時間を短縮できます。

文字コードの違いによる問題をどう解決する?

文字コードの違いによる問題を解決するためには、以下の方法を考慮してください。

  • 文字コードの確認: CSVファイルの文字コードを事前に確認し、プログラムで使用する文字コードと一致させるようにします。
  • 文字コード変換ライブラリの使用: iconvmbstowcsなどのライブラリを使用して、文字コードを変換します。
  • UTF-8の使用: 可能であれば、UTF-8を標準の文字コードとして使用することで、多くの文字コードの問題を回避できます。

大規模なCSVファイルを扱う際の注意点は?

大規模なCSVファイルを扱う際には、以下の点に注意してください。

  • メモリ使用量の管理: 大きなファイルを一度にメモリに読み込むと、メモリ不足になる可能性があります。

必要な部分だけを読み込むようにします。

  • 効率的なデータ処理: データの処理を効率的に行うために、アルゴリズムの最適化やデータ構造の選択を慎重に行います。
  • ファイルの分割: ファイルが非常に大きい場合、処理しやすいサイズに分割することを検討します。

まとめ

CSVファイルをC言語で扱う際の基本的な手順と応用例、エラーハンドリングについて学びました。

これにより、CSVファイルの読み込みやデータ処理の基礎を理解し、実際のプログラムに応用できるようになります。

この記事を参考に、CSVファイルを効率的に扱うプログラムを作成し、データ処理のスキルを向上させましょう。

当サイトはリンクフリーです。出典元を明記していただければ、ご自由に引用していただいて構いません。

関連カテゴリーから探す

  • 標準入出力 (47)
  • ファイル (76)
  • URLをコピーしました!
目次から探す