【问题标题】:Reading data from a .dat binary file从 .dat 二进制文件中读取数据
【发布时间】:2015-06-27 10:49:08
【问题描述】:

我有一个 .dat 文件需要读取并为人们打印记录 具有指定为命令行参数的属性。该文件的格式如下。每个人的记录以一个无符号的 32 位整数开头,其中包含有关此人的各种信息:

0-4 : 名字的长度(key=first)

5-9 : 中间名的长度 (key=middle)

10-14 : 姓氏长度 (key=last)

15-21 : 年龄 (key=age)

22:性别(0=男性,1=女性)(键=性别)

23-28 : 状态(0 到 49 按字母顺序排列)(key=state)

29 : 当前已婚 (0=false, 1=true) (key=married)

30 : 全职工作 (0=false, 1=true) (key=employed)

31 : 上过大学 (0=false, 1=true) (key=college)

我想我想先读取整个 32 位(4 个字节),然后从 32 位整数中逐位读取。我是 fread 和 fseek 的新手,所以我真的不知道我是否走在正确的轨道上,任何帮助将不胜感激。到目前为止,这是我的代码。

  int main(int argc, char *argv[]) {

  char *buf;
  long lSize;
  size_t result;

  FILE *fp;
  fp = fopen("/u1/junk/people.dat","r");
  if(fp == NULL) {
    printf("Error: can't open file to read\n");
    return -1;
  }
  else {
    printf("File people.dat opened successfully to read\n");
  }


  //obtian file size
  fseek(fp, 0, SEEK_END);
  lSize = ftell(fp);
  rewind(fp);

  //allocate memory to contain the whole file
  buf = (char*) malloc (sizeof(char)*lSize);

  while (!feof(fp)) {
    fread(buf, 4, 1, fp);
    fseek(fp, i, SEEK_CUR);
    fread(buf, 32, 1, fp);
    printf("%s\n", buf);
    i+=32;
  }

  fclose(fp);
  return 0;  
}

【问题讨论】:

  • 两个基本提示:不要在 C 中强制转换 malloc() 的返回值,不要像这样使用 feof() 来检测文件结尾。
  • 我觉得你应该想出一个带有位域的结构,一口气读完全部信息。
  • @facebook-100001358991487 我不同意,因为这不是可移植的实现,尽管 OP 没有提到他们是否需要可移植性。我希望看到 OP 逐个字段地填充结构。
  • @siliconwafer 为什么它不是可移植的实现?
  • @facebook-100001358991487 硅片,感谢您的建议。我不需要可移植性,位域建议听起来很棒。我现在遇到的问题是如何获取 32 位整数,然后我可以将它们与我的结构成员进行比较。

标签: c file binaryfiles fread


【解决方案1】:
#include <stdio.h>

// define first 32 bits of record
struct personRecord
{
    unsigned first    :5;
    unsigned middle   :5;
    unsigned last     :5;
    unsigned age      :7;
    unsigned sex      :1;
    unsigned state    :6;
    unsigned married  :1;
    unsigned employed :1;
    unsigned college  :1;
};

// prototypes
void processRecord(FILE* fp, char* buf);


int main(int argc, char *argv[])
{

    struct personRecord key;

    FILE *fp;
    fp = fopen("/u1/junk/people.dat","r");
    if(fp == NULL)
    {
        printf("Error: can't open file to read\n");
        return -1;
    }

    // implied else, fopen successful

    printf("File people.dat opened successfully to read\n");



    while ( 1 == fread( &key, 4, 1, fp ) )
    {
        processRecord(fp, key);
    }

    fclose(fp);
    return 0;
} // end function: main



void processRecord(FILE* fp, personRecord key)
{
      int result;
      int bufFirst[key.first] = {'\0'};
      ...

      // use  lengths to determine how much more  bytes to read for each field
      result = fread( bufFirst, key.first, 1, fp );
      if ( result == key.first )
      { // then successful acquire first name
          ...
      }
      ...
      // first, middle, last,

      // use lookup table to get state name from state field
      char * pState = alphabeticalState[key.state];

      // do something with the extracted info
      ...
} // end function: processRecord


const char * alphabeticalStates[] =
{
    "alabama";
    ...
    "washington";
    "wisconsin";
};

【讨论】:

  • 如果您希望字段first、middle、last为字符串,则使每个数组为name+1的最大长度,并使用fgets而不是fread来输入值
【解决方案2】:

这是未经测试的,但希望能让您了解“蒙版和移位”技术。你可以阅读更多关于它的信息: What are bitwise shift (bit-shift) operators and how do they work?Bitfield manipulation in C

假设您读取了无符号的 32 位整数:

unsigned long myint;
fread(&myint, sizeof(myint), 1, fid);

现在,使用 shift 和 mask 提取值。

// bits 0-4 (5 bits)
unsigned long firstNameLength = myint & 0xF1;

// bit 31
unsigned long attendedCollege = (myint & 0x0000000E) << 31;

【讨论】:

  • 这一行:'unsigned long AttendCollege = (myint & 0x0000000E) > 31;'顺便说一句:不能保证 'long int' 是 4 个字节,唯一的保证是它至少是 4 个字节。就我们的目的而言,最好声明一个由 4 个字符组成的数组并操作其内容。
猜你喜欢
  • 2012-08-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-18
  • 2015-04-23
  • 2018-01-16
  • 1970-01-01
  • 1970-01-01
  • 2015-02-19
相关资源
最近更新 更多