challenge 固定長データ

固定長のデータが記載されたファイルを読み込むプログラムを作成してください。読み込んだデータは、複数の値を格納できるデータ型に格納してください。

ファイルには、すべて ascii 文字で以下のデータが格納されています。デリミタはなく、固定長で格納されています。レコードとレコードのあいだも改行はありません。

  1. 姓 (12文字) 文字数が足りない場合は、後ろを空白で埋めてあります。
  2. 名 (12文字) 文字数が足りない場合は、後ろを空白で埋めてあります。
  3. 性別 (F,M,Uの3種類、1文字)
  4. 年齢 (3桁の数字、桁数が足りない場合は、ゼロで埋めず、頭を空白で埋めてあります。
  5. 年 2008 固定
  6. 月 03 固定
  7. さらに以下のデータが日付分くりかえされます。
    1. 日付 (01 〜 31) 2文字
    2. 朝食のメニュー (500文字)
    3. 昼食のメニュー (500文字)
    4. 夕食のメニュー (500文字)

以上の形式のデータ500人分を読みこんで、データを複数の値を格納できるデータ型に格納してください。データに大して何か処理を行う必要はなく、すぐに破棄してかまいません。

この問題は、このようなファイルをどのように扱うかを知りたくて作成しました。

Posted feedbacks - Flatten

Nested Hidden
投稿速さ重視で
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
using System;
using System.Collections.Generic;
using System.IO;
struct MenuList
{
    public string Day;
    public string Firstbread;
    public string Lunch;
    public string Dinner;
}

struct Record
{
    public string FirstName;
    public string SecondName;
    public string Sex;
    public string Age;
    public string Year;
    public string Month;
    public List<MenuList> Menu;
}

class Program
{
    static void Main(string[] args)
    {
        List<Record> meibo = new List<Record>();

        //テストデータ作成
        using (StreamWriter sw = new StreamWriter(@"C:\testdata.txt"))
        {
            for (int i = 0; i < 500; i++)
            {
                sw.Write("{0, -12}", "Yamada");
                sw.Write("{0, -12}", "Tarou");
                sw.Write("{0,   1}", "M");
                sw.Write("{0,   3}", "26");
                sw.Write("{0,   4}", "2008");
                sw.Write("{0,   2}", "03");
                for (int j = 1; j <= 31; j++)
                {
                    sw.Write("{0:00}", j);
                    sw.Write("{0,-500}", "Yamada");
                    sw.Write("{0,-500}", "Yamada");
                    sw.Write("{0,-500}", "Yamada");
                }
            }
            sw.Dispose();
        }


        using (StreamReader sr = new StreamReader(@"C:\testdata.txt"))
        {
            Record temp;
            while (!sr.EndOfStream)
            {
                temp = new Record();
                char[] buffer;
                
                //性
                buffer = new char[12];
                sr.Read(buffer, 0, buffer.Length);
                temp.FirstName = string.Format("{0:s12}", new string(buffer));

                //名
                buffer = new char[12];
                sr.Read(buffer, 0, buffer.Length);
                temp.SecondName = string.Format("{0:s12}", new string(buffer));

                //性別
                buffer = new char[1];
                sr.Read(buffer, 0, buffer.Length);
                temp.Sex = string.Format("{0:s1}", new string(buffer));

                //年齢
                buffer = new char[3];
                sr.Read(buffer, 0, buffer.Length);
                temp.Age = string.Format("{0,3:s3}", new string(buffer));
                
                //年
                buffer = new char[4];
                sr.Read(buffer, 0, buffer.Length);
                temp.Year = string.Format("{0:s4}", new string(buffer));

                //月
                buffer = new char[2];
                sr.Read(buffer, 0, buffer.Length);
                temp.Month = string.Format("{0:s2}", new string(buffer));

                //ループ
                temp.Menu = new List<MenuList>();
                for (int i = 1; i <= 31; i++)
                {
                    MenuList temp2 = new MenuList();
                    //日
                    buffer = new char[2];
                    sr.Read(buffer, 0, buffer.Length);
                    temp2.Day = string.Format("{0:s2}", new string(buffer));

                    //朝食
                    buffer = new char[500];
                    sr.Read(buffer, 0, buffer.Length);
                    temp2.Firstbread = string.Format("{0:s500}", new string(buffer));

                    //昼食
                    buffer = new char[500];
                    sr.Read(buffer, 0, buffer.Length);
                    temp2.Lunch = string.Format("{0:s500}", new string(buffer));


                    //夕食
                    buffer = new char[500];
                    sr.Read(buffer, 0, buffer.Length);
                    temp2.Dinner = string.Format("{0:s500}", new string(buffer));

                    temp.Menu.Add(temp2);
                }

                meibo.Add(temp);
            }

            foreach (Record result in meibo)
            {
                Console.WriteLine("FirstName : {0}", result.FirstName);
                Console.WriteLine("SecondName : {0}", result.SecondName);
                Console.WriteLine("Sex : {0}", result.Sex);
                Console.WriteLine("Age : {0}", result.Age);
                Console.WriteLine("Year : {0}", result.Year);
                Console.WriteLine("Month : {0}", result.Month);
                foreach (MenuList result2 in result.Menu)
                {
                    Console.WriteLine("Day : {0}", result2.Day);
                    Console.WriteLine("Firstbread : {0}", result2.Firstbread);
                    Console.WriteLine("Lunch : {0}", result2.Lunch);
                    Console.WriteLine("Dinner : {0}", result2.Dinner);
                }
            }
            sr.Dispose();
        }
    }
}

Squeak Smalltalk で。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
| stream data |
stream := FileStream fileNamed: 'data.txt'.
data := OrderedCollection new.
500 timesRepeat: [
    | record |
    record := OrderedCollection new.
    #(12 12 1 3 4 2) do: [:size | record add: (stream next: size) withBlanksTrimmed].
    1 to: 31 do: [:date |
        record add: (stream next: 2).
        3 timesRepeat: [record add: (stream next: 500) withBlanksTrimmed]].
    data add: record].
stream close.
data inspect

ごく普通に。
しかしC系の人間にしかわからないバウンダリの痛み。
このデータ仕様わざとやってるでしょ?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <stdio.h>
#include <stdlib.h>

typedef struct tagDailyMenu {
    char date[2];
    char breakfast[500];
    char lunch[500];
    char dinnar[500];
} DailyMenu;

typedef struct tagPerson {
    char family[12];
    char name[12];
    char sex;
    char age[3];
    char year[4];
    char month[3];
} Person;

typedef struct tagRecord {
    Person person;
    DailyMenu days[31];
} Record;

int main(void)
{
    FILE *fp;
    char *filename = "data.dat";
    int readlen = 0;
    Record rec;

    fp = fopen(filename, "r");
    if (fp == NULL) {
        printf("ファイルオープン失敗\n");
        return 1;
    }

    memset(&rec, 0x00, sizeof(Record));
    while ((readlen = fread(&rec.person, 34, 1, fp)) == 1) {

        int readlen2 = 0;
        int day = 0;

        for (day = 0; day < 31; day++) {
            int readlen2 = fread(&rec.days[day], 1502, 1, fp);
            if (readlen2 < 1) {
                printf("ファイルがこわれています。\n");
                break;
            }
        }
        if (day < 31) {
            break;
        }
        printf("name: [%.12s %.12s] %.4s/%.2s [%.2s/%.10s/%.10s/%.10s]\n",
            rec.person.family, rec.person.name,
            rec.person.year, rec.person.month,
            rec.days[0].date, rec.days[30].breakfast,
            rec.days[30].lunch, rec.days[30].dinnar
            );

        memset(&rec, 0x00, sizeof(Record));
    }
    fclose(fp);
    return 0;
}

やっつけですがunpackを使った例。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/usr/bin/perl

use strict;
use warnings;

my $dat;
if (@ARGV) {
  open $dat, shift or die;
} else {
  $dat = \*STDIN;
}

my $bytes;
my @records;

for (1..500) {
  read $dat, $bytes, 12 + 12 + 1 + 3 + 4 + 2;
  my ($lname, $fname, $sex, $age, $year, $month) = unpack "A12A12A1A3A4A2", $bytes;
  $lname =~ s/\s*$//;
  $fname =~ s/\s*$//;
  my %record = (last_name => $lname,
             first_name => $fname,
         sex => $sex,
         age => $age + 0,
         year => $year + 0,
         month => $month + 0,
         menues => []);
  for (1..31) {
    read $dat, $bytes, 2 + 500 + 500 + 500;
    my ($day, $breakfast, $lunch, $dinner) = unpack "A2A500A500A500", $bytes;
    $breakfast =~ s/^\s*|\s*$//;
    $lunch =~ s/^\s*|\s*$//;
    $dinner =~ s/^\s*|\s*$//;
    push @{$record{menues}}, {day => $day + 0,
                   breakfast => $breakfast,
                   lunch => $lunch,
                   dinner => $dinner};
  }
  push @records, \%record;
}

#テスト出力
use Data::Dumper;
print Dumper @records;

とりあえず、こんな感じで。 ちゃんとやるなら、ReadとWriteの処理はRecordとセットのクラスを用意するかも。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Sample170 {
    private static final String encoding = "MS932";
    private static final String FILE_NAME = "record.dat";
    
    public static void main(String[] args) {
        try {
            createTestData(FILE_NAME);

            List<Record> records = readData(FILE_NAME);
            System.out.println(records.size());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static List<Record> readData(String fileName) throws IOException {
        Reader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), encoding));
            List<Record> result = new ArrayList<Record>();
            char[] smallBuf = new char[12];
            char[] menuBuf = new char[500];
            while (true) {
                Record record = new Record();
                if (reader.read(smallBuf) < 0) break;
                record.familyName = String.valueOf(smallBuf).trim();
                if (reader.read(smallBuf) < 0) break;
                record.firstName = String.valueOf(smallBuf).trim();
                if (reader.read(smallBuf, 0 , 1) < 0) break;
                record.sex = Record.Sex.valueOf(String.valueOf(smallBuf[0]));
                if (reader.read(smallBuf, 0 , 3) < 0) break;
                record.age = Integer.parseInt(String.valueOf(smallBuf, 0, 3).trim());
                
                if (reader.read(smallBuf, 0 , 4) < 0) break;
                int year = Integer.parseInt(String.valueOf(smallBuf, 0, 4).trim());
                if (reader.read(smallBuf, 0 , 2) < 0) break;
                int month = Integer.parseInt(String.valueOf(smallBuf, 0, 2).trim());
                for (int index = 1; index <= 31; index++) {
                    MenuData menu = new MenuData();
                    menu.year = year;
                    menu.month = month;
                    
                    if (reader.read(smallBuf, 0 , 2) < 0) break;
                    menu.day = Integer.parseInt(String.valueOf(smallBuf, 0, 2).trim());
                    if (reader.read(menuBuf) < 0) break;
                    menu.breakfast = String.valueOf(menuBuf).trim();
                    if (reader.read(menuBuf) < 0) break;
                    menu.lunch = String.valueOf(menuBuf).trim();
                    if (reader.read(menuBuf) < 0) break;
                    menu.dinner = String.valueOf(menuBuf).trim();
                }
                result.add(record);
            }
            return result;
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
    }

    private static void createTestData(String fileName) throws IOException {
        Writer writer = null;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), encoding));
            Random random = new Random();
            Record.Sex[] sexValues = Record.Sex.values();
            for (int index = 0; index < 500; index++) {
                writer.write(String.format("%-12s", "FamilyName"));
                writer.write(String.format("%-12s", "FirstName"));
                writer.write(sexValues[random.nextInt(sexValues.length)].toString());
                writer.write(String.format("%3d", random.nextInt(120)));
                writer.write("2008");
                writer.write("03");
                for (int day = 1; day <= 31; day++) {
                    writer.write(String.format("%02d", day));
                    writer.write(String.format("%-500s", "breakfast menu."));
                    writer.write(String.format("%-500s", "lunch menu."));
                    writer.write(String.format("%-500s", "dinner menu."));
                }
            }

        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }
}

class Record {
    public enum Sex {
        F, M, U,
    }
    public String familyName;
    public String firstName;
    public Sex sex;
    public int age;
    public final List<MenuData> menuList = new ArrayList<MenuData>();
}

class MenuData {
    public int year;
    public int month;
    public int day;
    public String breakfast;
    public String lunch;
    public String dinner;
}

エラー処理をはしょればこんなかんじ? あと、31日固定として。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <stdlib.h>

typedef struct menu_ {
  char date[2];
  char breakfast[500];
  char lunch[500];
  char supper[500];
} menu_t;

typedef struct fixed_ {
  char last_name[12];
  char first_name[12];
  char gender;
  char age[3];
  char year[4];
  char month[3];
  menu_t menus[31];
} fixed_t;

int main(int argc, char **argv) {
  FILE *fp = fopen(argv[1], "r");
  fixed_t fixed[500];
  int i;

  for (i=0; i<500; i++) {
    fread(&fixed[i], sizeof(fixed_t), 1, fp);
  }

  return 0;
}

匿名で書いてしまいました。mootohです。


ついでにテストデータ生成スクリプトを貼っておきます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/perl

use strict;
use warnings;

my @lnames = map { sprintf "%-12s", $_ } qw/Foo Bar Baz Jim Bob Beth Cathy/;
my @fnames =
  map { sprintf "%-12s", $_ } qw/Hoge Fuga Piyo Jacson Page McDonald Hamond/;
my @sexes = qw/F M U/;
my @ages = map { sprintf "%03d", $_ } 0 .. 999;
my @dishes =
  map { sprintf "%-500s", $_ }
  qw/BaconEgg Coffee HamEgg BoiledEgg EggInBasket Udon Steak
  SunnySideUp Onigiri Ramen/;

sub randomint { int rand shift }

for ( 1 .. 500 ) {
    print $lnames[ randomint( scalar @fnames ) ],
      $fnames[ randomint( scalar @lnames ) ],
      $sexes[ randomint( scalar @sexes ) ], $ages[ randomint( scalar @ages ) ],
      "200803";
    for my $day ( 1 .. 31 ) {
        $day = sprintf "%02d", $day;
        print $day, $dishes[ randomint( scalar @dishes ) ],
          $dishes[ randomint( scalar @dishes ) ],
          $dishes[ randomint( scalar @dishes ) ];
    }
}

dinnerのつづりを素で間違えてる。。。

バウンダリとは、実行効率のためCのコンパイラが自動的に構造体のサイズを4バイトの整数倍にしてしまうことです。
日毎の部分の本当のサイズは1502バイトですが、構造体のサイズは1504バイトになってしまい、シンプルに書くことができませんでした。
本当はfreadのサイズ指定で数値ではなくsizeofを使いたかった。

なおRecordとPersonを分離しているのは、最初、日ごとのデータが31個固定ではなく可変数だと思い込んでいたためです。

COBOLで書くべきお題がついにきましたね(笑

読み込み処理はfromStringです。テストデータ作成用にtoStringを作成しています。

matchというのが予約語なので、「match」というメソッドが素直に呼び出せないという・・・

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.io._
import java.util.Scanner
import java.util.regex._
import scala.io._

object Meal {
  def fromString(text:String) = {
    val scanner = new Scanner(text)
    scanner.findInLine("^(.{12})(.{12})(.{1})(.{3})(.{4})(.{2})
                         (.{2})(.{500})(.{500})(.{500})$")
    val data = classOf[Scanner].getMethod("match",null).
               invoke(scanner,null).  asInstanceOf[MatchResult].group _:int=>String
    new Meal( data(1).trim, data(2).trim, data(3)(0), data(4).trim.toInt,
              data(5).trim.toInt, data(6).trim.toInt, data(7).trim.toInt, 
              data(8), data(9), data(10))
  }
}

class Meal 
  (var lastName:String, var firstName:String, var sex:char, 
   var age:int, var year:int, var month:int, var day:int,
   var breakfast:String, var lunch:String, var dinner:String) {

  def format(template:String, arg:Any*) = {
    String.format(template, arg.map(_.asInstanceOf[AnyRef]).toArray)
  }

  override def toString = {
    format("%-12s%-12s%c%3d%04d%02d%02d%-500s%-500s%-500s\n",
           lastName, firstName, sex, age, year, month, day,
           breakfast, lunch, dinner)
  }

}

Source.fromFile("test.txt").getLines.take(500) foreach Meal.fromString

すみません。バウンダリ関係なかった! Personのmonthの桁数が3になっているのに気づかず混乱してしまった。 全部charだとバウンダリ関係ないんだっけ。 落ち着け俺。


今回の問題とは関係ないですが、一応知ってるとは思いますが、知らない人のために。

#pragmaなのでコンパイラ依存ですが、4byte境界を変更することができます。

次のような構造体をsizeofすると、5になります。
また、pragma packを取り除くと、8になります。

#BMPのローダーを書くときにお世話になったなぁ。
#頭の'BM'って文字列のせいで、全部が2byteずつずれて・・・。
1
2
3
4
5
6
7
#pragma pack(push,1)
typedef struct s
{
    char ch1;
    int i1;
} s;
#pragma pack(pop)

メモリ上の構造≠ファイル上の構造の前提で書きました。 予想以上にstreamの扱いに苦戦。streamと固定長データは相性が良くない…というより、わたしがstreamを使い切れていないというのが正解かも。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <iterator>

struct Menu
{
    std::string date;
    std::string breakfast;
    std::string lunch;
    std::string dinner;
};

typedef std::vector<Menu> Menus;

struct Record
{
public:
    std::string lastName;
    std::string firstName;
    std::string sex;
    std::string age;
    std::string year;
    std::string month;
    Menus       menus;
};

std::istream& operator >> (std::istream& in, Menu& menu)
{
    char s[500];
    in.read(s, 2);   menu.date      = std::string(s, 2);
    in.read(s, 500); menu.breakfast = std::string(s, 500);
    in.read(s, 500); menu.lunch     = std::string(s, 500);
    in.read(s, 500); menu.dinner    = std::string(s, 500);

    return in;
}

std::istream& operator >> (std::istream& in, Record& record)
{
    char s[500];
    in.read(s, 12); record.lastName  = std::string(s, 12);
    in.read(s, 12); record.firstName = std::string(s, 12);
    in.read(s,  1); record.sex       = std::string(s,  1);
    in.read(s,  3); record.age       = std::string(s,  3);
    in.read(s,  4); record.year      = std::string(s,  4);
    in.read(s,  2); record.month     = std::string(s,  2);

    std::istream_iterator<Menu> itr(in);
    for(int i = 0; i < 31; ++i)
    {
        record.menus.push_back(*itr++);
    }

    return in;
}

#include <fstream>

void read(const std::string& filename, std::vector<Record>& records)
{
    records.clear();

    std::ifstream source(filename.c_str(), std::ios::binary);

    std::istream_iterator<Record> itr(source);
    for(int i = 0; i < 500; ++i)
    {
        records.push_back(*itr++);
    }
}

// 以下はテストデータを作成するためのコードです。

std::ostream& operator << (std::ostream& out, const Menu& menu)
{
    std::ios::fmtflags flags = out.flags();
    out.setf(std::ios::left);
    out << std::setw(2)   << menu.date;
    out << std::setw(500) << menu.breakfast;
    out << std::setw(500) << menu.lunch;
    out << std::setw(500) << menu.dinner;
    out.flags(flags);

    return out;
}

std::ostream& operator << (std::ostream& out, const Record& record)
{
    std::ios::fmtflags flags = out.flags();
    out.setf(std::ios::left);
    out << std::setw(12) << record.lastName;
    out << std::setw(12) << record.firstName;
    out << std::setw(1)  << record.sex;
    out << std::setw(3)  << record.age;
    out << std::setw(4)  << record.year;
    out << std::setw(2)  << record.month;
    out.flags(flags);

    for(int i = 0; i < 31; ++i)
    {
        out << record.menus[i];
    }

    return out;
}

#include <sstream>

std::string toString(int value, int col)
{
    std::stringstream s;
    s << std::setfill('0') << std::setw(col) << value;
    return s.str();
}

void write(const std::string& filename)
{
    Record record;

    record.lastName  = "LASTNAME";
    record.firstName = "Firstname";
    record.sex       = "U";
    record.age       = " 99";
    record.year      = "2008";
    record.month     = "03";

    Menu menu;

    menu.breakfast = "breakfast";
    menu.lunch     = "lunch";
    menu.dinner    = "dinner";

    for(int i = 0; i < 31; ++i)
    {
        menu.date = toString(i + 1, 2);
        record.menus.push_back(menu);
    }

    std::ofstream file(filename.c_str(), std::ios::binary);

    for(int i = 0; i < 500; ++i)
    {
        file << record;
    }
}

検証等全く行ってない一発書きですが、とりあえず。 普通は配列に取込んだ後、DBに格納したりする訳ですが、今回データの加工は要らないそうなので、そのままです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
$path = "./";
$file = "data.txt";
$rsz  = 46596;</