从具有可变长度记录的二进制文件读取

时间:2009-05-07 15:43:51

标签: c file-io binary

我有一个带有可变长度记录的二进制文件,看起来像这样:

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之间的数字,第二个数字是部门,它可以在1之间和10。 正如您在文件中看到的那样,课程名称和部门编号之间没有空格。

问题是如何从二进制文件中读取?文件中没有字段告诉我字符串的大小是什么,课程名称是什么。 我可以读第一个int(课程ID),但我怎么知道课程名称的大小?

6 个答案:

答案 0 :(得分:3)

fscanf()与格式字符串"%u %[a-z]%u"一起使用。

这是一个完整的示例程序:

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

答案 1 :(得分:1)

正如其他人所说,这看起来很像文本,因此文本解析方法可能是正确的方法。由于这是家庭作业,我不会为你编写代码,但这是我采取的一般方法:

  • 使用fscanf,阅读课程代码,以及带有名称和部门代码的组合字符串。
  • 从组合字符串的末尾开始,向后搜索,直到找到第一个非数字。这是课程名称的结尾。
  • 读取从课程名称末尾开始的整数(即我们发现向后扫描的最后一位数字)。
  • 用NUL('\ 0')替换该整数字符串部分的第一个字符 - 这会在课程名称后面立即终止组合字符串。所以我们在组合字符串中留下的是课程名称,我们在整数变量中包含课程代码和部门代码。
  • 重复下一行。

答案 2 :(得分:0)

要读取可变长度记录,您应该使用某种约定。例如,表示记录结束的特殊字符。在每条记录中,您可以使用另一个指示字段结尾的特殊字符。

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

答案 3 :(得分:0)

您首先需要知道文件是如何写出来的。

答案 4 :(得分:0)

如果课程代码和课程名称(包括部门代码)之间存在一对一的对应关系,您可以从代码中推断出课程名称的大小,在代码或配置文件中的某个位置使用预定义的表格。

如果没有,我看到的主要问题是区分music1music10等内容。

答案 5 :(得分:0)

假设没有回车符,并且每个字符串都以空值终止。 我写了一个小程序来创建一个二进制文件,然后再读回来,产生类似的输出。


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