C言語でファイルを読み込み配列にデータを格納する
- 作成日: 2024-03-22
- 更新日: 2024-03-22
- カテゴリ: C言語
C言語でファイルを読み込み、そのデータを配列に格納する方法を解説します。
C言語や他の言語を扱うYoutubeも公開しています。
興味がある方は以下のリンクからご覧ください。
固定長の配列にデータを読み込む
固定長のデータの配列にファイル内容を読み込むサンプルは以下になります。
#include <stdio.h>
enum {
DATA_LEN = 256, // データの長さ
};
int main(void) {
// 読み込み先のデータ
char data[DATA_LEN + 1]; // + 1はナル文字用
// ファイルを開く
FILE *fin = fopen("sample.txt", "r");
if (fin == NULL) {
perror("fin");
return 1;
}
// ファイル内容を読み込む
int nread = fread(data, sizeof(data[0]), DATA_LEN, fin);
data[nread] = '\0'; // ナル文字を付加
// データ内容を出力
printf("data[%s]\n", data);
// ファイルを閉じる
fclose(fin);
return 0;
}
上記のコードを実行すると以下のような結果になります。
data[Hello, World!
Good World!
Goodbye, World!
]
#include <stdio.h>
上記ではstdio.h
をインクルードしています。printf
関数やfopen
関数を使う場合はこのヘッダーをインクルードします。
enum {
DATA_LEN = 256, // データの長さ
};
上記ではenum
でDATA_LEN
という定数を定義しています。
DATA_LEN
はデータの保存先の配列の長さです。
ここではとりあえず256にしています。もっと大きなデータにした場合は適時値を変えてください。
// 読み込み先のデータ
char data[DATA_LEN + 1]; // + 1はナル文字用
上記では配列であるdata
を定義しています。
配列の要素数はDATA_LEN + 1
になります。
+ 1
にしているのは配列の末尾に格納するナル文字のためです。
C言語では配列を文字列として扱う場合は配列の末尾にナル文字のスペースがないといけません。
// ファイルを開く
FILE *fin = fopen("sample.txt", "r");
if (fin == NULL) {
perror("fin");
return 1;
}
上記ではファイルをfopen
関数で開いています。
fopen
関数は第1引数のパスを第2引数のモードで開きます。
#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);
さきほどのコードではモードはr
にしています。
これはテキストファイルを読み込む時のモードです。
バイナリにしたい場合はrb
にします。
fin
がファイルポインタですが、これがNULL
の場合はperror
関数でエラーを出力します。
#include <stdio.h>
void perror(const char *s);
perror
関数は引数の文字列を標準エラーに出力し、そのあとにerrno
を文字列にしたものを付加します。
errno
とはエラーを表すグローバル変数のことです。C言語ではこのerrno
でエラー処理することが多いです。
関連記事
C言語のerrnoの使い方: 初期化、文字列化、参照、ハンドリング方法の具体例
// ファイル内容を読み込む
int nread = fread(data, sizeof(data[0]), DATA_LEN, fin);
上記ではfread
関数でファイル内容を読み込み、配列data
に保存しています。
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
fread
関数は第1引数にデータ保存先のバッファのポインタを取ります。
第2引数にはそのバッファの要素1つのサイズ(バイト数)を取ります。
第3引数にはバッファの要素数を取ります。
第4引数にはファイルポインタ(ストリーム)を指定します。
fread
は読み込みに成功すると読み込んだ要素数を返します。
data[nread] = '\0'; // ナル文字を付加
上記ではdata[nread]
の位置にナル文字を入れています。
fread
関数が返した読み込んだ要素数をdata
の添え字にして、そこにナル文字を入れています。
文字列の配列はお尻にナル文字が必要です。
// データ内容を出力
printf("data[%s]\n", data);
// ファイルを閉じる
fclose(fin);
上記ではdata
を出力してfin
を閉じています。
fin
を閉じ忘れるとメモリリークなどのバグになります。
動的に配列を作成しデータを読み込む
固定長の配列ではなく動的に配列を作成してデータを読み込む方法です。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
// ファイルを開く
FILE *fp = fopen("sample.txt", "r");
if (fp == NULL) {
perror("fopen");
return 1;
}
fseek(fp, 0L, SEEK_END); // ファイル末尾にシーク
long pos = ftell(fp); // ファイル末尾の位置を得る。これがファイルサイズになる
long size = pos + 1; // + 1してナル文字分追加
fseek(fp, 0L, SEEK_SET); // 位置をファイル先頭に戻す
char *s = malloc(size); // 動的メモリを確保
if (s == NULL) {
perror("malloc");
fclose(fp);
return 1;
}
fread(s, sizeof(s[0]), pos, fp); // ファイル内容を読み込み
s[pos] = '\0'; // ナル文字を付加
// ファイル内容の出力
printf("data[%s]\n", s);
// ファイルを閉じる
fclose(fp);
// メモリを解放
free(s);
return 0;
}
上記のコードを実行すると以下の結果になります。
data[Hello, World!
Good World!
Goodbye, World!
]
// ファイルを開く
FILE *fp = fopen("sample.txt", "r");
if (fp == NULL) {
perror("fopen");
return 1;
}
上記ではファイルを開いています。ここは固定長の時と同じです。
fseek(fp, 0L, SEEK_END); // ファイル末尾にシーク
long pos = ftell(fp); // ファイル末尾の位置を得る。これがファイルサイズになる
long size = pos + 1; // + 1してナル文字分追加
fseek(fp, 0L, SEEK_SET); // 位置をファイル先頭に戻す
上記ではファイルポインタfp
からファイルサイズを取得しています。
まずfseek
関数でfp
の位置をファイル末尾にします。
それからftell
関数でファイル内の位置を取得してpos
に保存します。
そいてpos
にナル文字分の1
を足してsize
に保存します。
size
が取得出来たらfp
の位置を再びファイル先頭に戻します。
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
上記のfseek
関数は引数stream
の内部位置を変更します。
whence
の位置からoffset
だけ移動させます。
whence
には以下の定数を指定できます。
- SEEK_SET ... ファイル先頭
- SEEK_CUR ... 現在位置
- SEEK_END ... ファイル末尾
#include <stdio.h>
long ftell(FILE *stream);
上記のftell
関数は引数stream
の内部位置を取得します。
char *s = malloc(size); // 動的メモリを確保
if (s == NULL) {
perror("malloc");
fclose(fp);
return 1;
}
上記では動的メモリを確保しています。
動的メモリとはヒープ領域から取ってくるメモリのことです。
メインメモリ上の大きなメモリを扱えます。
malloc
関数でsize
のバイトだけメモリを確保してそれをs
に入れます。
s
がNULLだったらperror
関数でエラーを出力してfclose
関数でファイルポインタを閉じてからreturn
します。
#include <stdlib.h>
void *malloc(size_t size);
上記のmalloc
関数は引数のsize
バイトだけヒープ領域からメモリを確保します。
malloc
関数はメモリの確保に失敗するとNULLを返し、成功した場合は確保したメモリのアドレスを返します。
fread(s, sizeof(s[0]), pos, fp); // ファイル内容を読み込み
s[pos] = '\0'; // ナル文字を付加
上記ではfread
関数を使ってファイル内容を読み込んでいます。
やってることは固定長の時と同じです。
// ファイル内容の出力
printf("data[%s]\n", s);
// ファイルを閉じる
fclose(fp);
// メモリを解放
free(s);
上記ではs
を出力し、ファイルを閉じてs
をfree()
しています。
s
はmalloc
関数で確保した動的メモリです。
動的メモリはfree
関数で解放する必要があります。
解放を忘れるとメモリリークと言うバグになります。
#include <stdlib.h>
void free(void *ptr);
上記のfree
関数は動的メモリで確保された引数ptr
のメモリを解放します。
関連記事
自作関数read_fileでファイルを読み込み【ファイル入出力, コマンド】
C言語の静的なメモリと動的なメモリ