質問

次のような可変長レコードのバイナリファイルがあります:

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;
}

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top