質問
次のような可変長レコードのバイナリファイルがあります:
12 economic10
13 science5
14 music1
15 physics9
16 chemistry9
17 history2
18 anatomy7
19 physiology7
20 literature3
21 fiction3
16 chemistry7
14 music10
20 literature1
コースの名前はファイル内の唯一の可変長レコードであり、最初の数字はコースのコードであり、1から9999までの数字であり、2番目の数字は部門で1の間ですおよび10。 ファイルにあるように、コース名と学部番号の間にスペースはありません。
問題は、バイナリファイルからどのように読み取ることができるかです。ファイルには、コース名である文字列のサイズを示すフィールドはありません。 最初のint(コースID)を読むことはできますが、コース名のサイズはどのようにわかりますか?
解決
フォーマット文字列"%u%[a-z]%u"
で fscanf()
を使用します。
完全なサンプルプログラムは次のとおりです。
#include <stdio.h>
#define NAME_MAX 64
int main(int argc, char ** argv)
{
FILE * file = fopen("foo.txt", "rb");
unsigned int course, department;
char name[NAME_MAX];
while(fscanf(file, "%u %[a-z]%u", &course, name, &department) != EOF)
{
// do stuff with records
printf("%u-%u %s\n", department, course, name);
}
fclose(file);
return 0;
}
他のヒント
他の人が言っているように、これはテキストによく似ているため、テキスト解析のアプローチが正しい方法である可能性があります。これは宿題なので、あなたのためにコーディングするつもりはありませんが、ここで私が取る一般的なアプローチを示します:
- fscanfを使用して、コースコード、および名前と学部コードを組み合わせた文字列を読み取ります。
- 結合された文字列の末尾から始めて、最初の非数字が見つかるまで逆方向に進みます。これでコース名の終わりです。
- コース名の末尾(つまり、逆方向にスキャンした最後の桁)の直後から整数を読み取ります。
- 文字列のその整数部分の最初の文字をNUL( '\ 0')に置き換えます-これにより、結合された文字列がコース名の直後で終了します。結合された文字列に残っているのはコース名だけであり、整数変数にコースコードと学科コードがあります。
- 次の行に繰り返します。
最初にファイルがどのように書き出されたかを知る必要があります。
コースコードとコース名(学部コードを含む)が1対1で対応している場合、コードまたは構成ファイルのどこかに事前定義されたテーブルを使用して、コードからコース名のサイズを推測できます。
そうでない場合、主な問題は music1
や music10
などを区別することです。
可変長レコードを読み取るには、何らかの規則を使用する必要があります。たとえば、レコードの終わりを示す特殊文字。すべてのレコード内で、フィールドの終わりを示す別の特殊文字を使用できます。
DO_READ read from file
is END_OF_RECORD char present?
yes: GOTO DO_PROCESS
no : GOTO DO_READ
DO_PROCESS read into buffer
is END_OF_FILE mark present?
yes: GOTO DOSOMETHINGWITHIT
no: GOTO DO_PROCESS
キャリッジリターンがなく、各文字列がヌルで終了していると仮定します。 バイナリファイルを作成して読み戻す小さなプログラムを作成し、同様の出力を生成しました。
// binaryFile.cpp
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#define BUFSIZE 64
int _tmain(int argc, _TCHAR* argv[])
{
FILE *f;
char buf[BUFSIZE+1];
// create dummy bin file
f = fopen("temp.bin","wb");
if (f)
{ // not writing all the data, just a few examples
sprintf(buf,"%04d%s\00",12,"economic10"); fwrite(buf,sizeof(char),strlen(buf)+1,f);
sprintf(buf,"%04d%s\00",13,"science5"); fwrite(buf,sizeof(char),strlen(buf)+1,f);
sprintf(buf,"%04d%s\00",14,"music1"); fwrite(buf,sizeof(char),strlen(buf)+1,f);
sprintf(buf,"%04d%s\00",15,"physics9"); fwrite(buf,sizeof(char),strlen(buf)+1,f);
fclose(f);
}
// read dummy bin file
f = fopen("temp.bin","rb");
if (f)
{
int classID;
char str[64];
char *pData
long offset = 0;
do
{
fseek(f,offset,SEEK_SET);
pData = fgets(buf,BUFSIZE,f);
if (pData)
{ sscanf(buf,"%04d%s",&classID,&str);
printf("%d\t%s\r\n",classID,str);
offset +=strlen(pData)+1; // record + 1 null character
}
} while(pData);
fclose(f);
}
getchar();
return 0;
}