C言語では、アプリの終了、再開時にデータを簡単に保存、再利用する方法として、
構造体をまるごとファイルに出力して、アプリの再開時にまるっと読み込むという、定番のテクニックがあります。

出力されたファイルは、CSVファイルと比べると人間の目には優しくないですが、
なんと言っても簡単ですし、バイナリエディタで見ればなんとか読めない事もありません。

■目次


1.構造体をファイルに出力する

// 構造体出力
// 1.バイナリモードで出力ファイルオープン
FILE *fpw = fopen("struct.dat", "wb");
// 2.構造体1個分出力
fwrite(&wStruct, sizeof(wStruct), 1, fpw);
// 3.出力ファイルクローズ
fclose(fpw);
 
  1. fopenでバイナリの書き込みモードでファイルを開きます。
  2. writeで構造体の先頭アドレスから、構造体のサイズ分だけ出力します。
  3. 出力ファイルをクローズします。

2.ファイルから構造体に読み込む

// 構造体読込
// 1.バイナリモードで読込ファイルオープン
FILE *fpr = fopen("struct.dat", "rb");
// 2.構造体1個分読込
fread(&rStruct, sizeof(rStruct), 1, fpr);
// 3.読込ファイルクローズ
fclose(fpr);
 
  1. fopenでバイナリの読み込みモードでファイルを開きます。
  2. read関数で構造体の先頭アドレスから、構造体のサイズ分だけファイルを読み込みます。
  3. 読込ファイルをクローズします。
  4. 読込は、出力の手順からfopenのパラメータと、「fwrite」が「fread」に変わるだけです。


3.サンプル

構造体を作成し、ファイルに書込、書き込んだファイルを読み込んで標準出力に読み込んだ結果を出力します。
#include <stdio.h>
#include <stdlib.h>
 
// テスト用構造体
struct Syain {
  long id;
  char name[20];
  int age;
  char tell[14];
  char email[20];
};
 
int main(void) {
  // 構造体作成
  struct Syain rStruct;
  struct Syain wStruct = { 2001, "新入社員A", 22, "000-0000-0000",
      "newsyain@example.com" };
 
  // 構造体出力
  // 1.バイナリモードで出力ファイルオープン
  FILE *fpw = fopen("struct.dat", "wb");
  // 2.構造体1個分出力
  fwrite(&wStruct, sizeof(wStruct), 1, fpw);
  // 3.出力ファイルクローズ
  fclose(fpw);
 
  // 構造体読込
  // 1.バイナリモードで読込ファイルオープン
  FILE *fpr = fopen("struct.dat", "rb");
  // 2.構造体1個分読込
  fread(&rStruct, sizeof(rStruct), 1, fpr);
  // 3.読込ファイルクローズ
  fclose(fpr);
 
  // 読み込んだ構造体を標準出力に書き出し
  printf("id = %ld\n", rStruct.id);
  printf("name = %s\n", rStruct.name);
  printf("age = %d\n", rStruct.age);
  printf("tell = %s\n", rStruct.tell);
  printf("email = %s\n", rStruct.email);
 
  return EXIT_SUCCESS;
}
 

3b.サンプル実行結果

id = 2001
name = 新入社員A
age = 22
tell = 000-0000-0000
email = newsyain@example.com
 

3c.サンプルダウンロード

サンプルソース cstructIO.c
構造体の出力結果 struct.dat

4.構造体の配列を読み書きする場合のサンプル

#include <stdio.h>
#include <stdlib.h>
 
// テスト用構造体
struct Syain {
  long id;
  char name[20];
  int age;
  char tell[14];
  char email[20];
};
 
int main(void) {
  // 構造体作成
  // ★変更点1 構造体を構造体の配列に変更★
  struct Syain rStruct[2];
  struct Syain wStruct[] = {
		  { 2001, "新入社員A", 22, "000-0000-0000", "newsyain@example.com" },
		  { 2002, "新入社員B", 23, "001-0001-0001", "newsyain2@example.com" }
  };
 
  // 構造体出力
  // 1.バイナリモードで出力ファイルオープン
  FILE *fpw = fopen("struct.dat", "wb");
  // 2.構造体の配列出力
  fwrite(&wStruct, sizeof(wStruct), 1, fpw);
  // 3.出力ファイルクローズ
  fclose(fpw);
 
  // 構造体読込
  // 1.バイナリモードで読込ファイルオープン
  FILE *fpr = fopen("struct.dat", "rb");
  // 2.構造体の配列に読込
  fread(&rStruct, sizeof(rStruct), 1, fpr);
  // 3.読込ファイルクローズ
  fclose(fpr);
 
  // 読み込んだ構造体を標準出力に書き出し
  printf("id = %ld\n", rStruct[0].id);
  printf("name = %s\n", rStruct[0].name);
  printf("age = %d\n", rStruct[0].age);
  printf("tell = %s\n", rStruct[0].tell);
  printf("email = %s\n", rStruct[0].email);
 
  // ★変更点2 構造体の内容出力★
  printf("id = %ld\n", rStruct[1].id);
  printf("name = %s\n", rStruct[1].name);
  printf("age = %d\n", rStruct[1].age);
  printf("tell = %s\n", rStruct[1].tell);
  printf("email = %s\n", rStruct[1].email);
 
  return EXIT_SUCCESS;
}
 
  • 構造体の配列を読み書きする場合も特に難しい事はありません。
  • sizeof(構造体の配列)で、構造体の配列全体のサイズを取得できるので、読み込みも書き込みも特に修正は不要です。

要注意!

  • ポインタ変数を含む構造体の入出力には気をつけてください。
  • ポインタを含む構造体を出力して、次に読み込んだ時、そのポインタは利用できないので初期化する必要があります。
  • 出来ればポインタ変数のない構造体を入出力してください。

コメント(バグ、間違い、こんな情報が欲しい等ありましたら)

  • テキストモードでの出力方法を教えてください。素人の人はそっちを使うことがあるかと思います。 - ななし 2016-01-06 19:38:08
名前:

アンケート(このページの情報はお役に立ちましたか?)

順位 選択肢 得票数 得票率 投票
1 役に立った 44 (50%) 投票済
2 かわいい 10 (11%)
3 分かりにくい 8 (9%)
4 しこりたい 6 (7%)
5 役に立たない 6 (7%)
6 眠い 5 (6%)
7 間違っている 5 (6%)
8 うざい 4 (5%)
その他
投票総数 88

添付ファイル