Fread二进制文件动态大小字符串

时间:2010-03-08 17:52:04

标签: c fread structure

我一直致力于这项任务,我需要读取“记录”并将其写入文件,然后能够在以后阅读/查找它们。在程序的每次运行中,用户可以决定编写新记录,或者读取旧记录(通过名称或#)

该文件是二进制文件,这是它的定义:

typedef struct{
        char * name;
        char * address;
        short addressLength, nameLength;
        int phoneNumber;
    }employeeRecord;
    employeeRecord record;

程序的工作方式,它将存储结构,然后是名称,然后是地址。名称和地址是动态分配的,这就是为什么必须首先读取结构以查找名称和地址的大小,为它们分配内存,然后将它们读入内存。

出于调试目的,我目前有两个程序。我有我的文件编写程序和文件读取。

我的实际问题是这样,当我读到我写的文件时,我在结构中读到,打印出手机#以确保它有效(哪种方法正常),然后记下名字(现在能够使用record.nameLength报告正确的值)。 但是,Fread不返回可用的名称,它返回空白。

我看到两个问题,要么我没有正确地将文件写入文件,要么我没有正确读取它。 这是我如何写入文件:其中fp是文件指针。 record.name是一个正确的值,因此是record.nameLength。我也写了包括空终止符的名字。 (例如'Jack \ 0')

fwrite(&record,sizeof record,1,fp);
fwrite(record.name,sizeof(char),record.nameLength,fp);
fwrite(record.address,sizeof(char),record.addressLength,fp);

然后我关闭文件。 这是我如何阅读文件:

fp = fopen("employeeRecord","r");


fread(&record,sizeof record,1,fp);
printf("Number: %d\n",record.phoneNumber);


char *nameString = malloc(sizeof(char)*record.nameLength);

printf("\nName Length: %d",record.nameLength);
fread(nameString,sizeof(char),record.nameLength,fp);
printf("\nName: %s",nameString);

注意那里有一些调试内容(名称长度和数字,两者都是正确的)。所以我知道文件打开正常,我可以使用名称长度罚款。为什么我的输出是空白的,换行符,或类似的东西? (输出只是名称:后面没有任何内容,程序完成就好了)

感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

我尝试了你的代码并且运行正常。按顺序,这里是输出,文件的hexdump,以及编译的源代码。

更新:更新了代码以从stdin或命令行参数中读取名称和地址。

prompt$ g++ -g -Wall -o test_records test_records.cpp
prompt$ echo -e "Test User\nSomeplace, Somewhere" | ./test_records
sizeof(employeeRecord) = 24
Number: 5551212

Name Length: 9
Name: Test User

prompt$ hexdump -C employeeRecord 
00000000  90 f7 bf 5f ff 7f 00 00  70 f7 bf 5f ff 7f 00 00  |..._....p.._....|
00000010  14 00 09 00 6c b4 54 00  54 65 73 74 20 55 73 65  |....l.T.Test Use|
00000020  72 53 6f 6d 65 70 6c 61  63 65 2c 20 53 6f 6d 65  |rSomeplace, Some|
00000030  77 68 65 72 65                                    |where|
00000035

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct{
        char * name;
        char * address;
        short addressLength, nameLength;
        int phoneNumber;
    }employeeRecord;

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

#if 0
  // Commmand line arguments
  if (argc < 3)
    return 1;

  record.nameLength = strlen(argv[1]);
  record.name = (char *)malloc(sizeof(char)*(record.nameLength + 1));
  strncpy(record.name, argv[1], record.nameLength + 1);

  record.addressLength = strlen(argv[2]);
  record.address = (char *)malloc(sizeof(char)*(record.addressLength + 1));
  strncpy(record.address, argv[2], record.addressLength + 1);
#else
  // stdin
  char input[1024];

  fgets(input, sizeof(input), stdin);
  record.nameLength = strlen(input);
  record.name = (char *)malloc(sizeof(char)*(record.nameLength + 1));
  strncpy(record.name, input, record.nameLength + 1);

  fgets(input, sizeof(input), stdin);
  record.addressLength = strlen(input);
  record.address = (char *)malloc(sizeof(char)*(record.addressLength + 1));
  strncpy(record.address, input, record.addressLength + 1);
#endif

  record.phoneNumber = 5551212;

  FILE *fp = NULL;

  printf("sizeof(employeeRecord) = %lu\n", sizeof(employeeRecord));

  // Write
  fp = fopen("employeeRecord","w");
  fwrite(&record,sizeof(employeeRecord),1,fp);
  // Note: we're not including terminating NULLs.
  fwrite(record.name,sizeof(char),record.nameLength,fp);
  fwrite(record.address,sizeof(char),record.addressLength,fp);
  fclose(fp);

  // Read
  fp = fopen("employeeRecord","r");
  fread(&record,sizeof(employeeRecord),1,fp);
  printf("Number: %d\n",record.phoneNumber);

  char *nameString = (char *)malloc(sizeof(char)*(record.nameLength + 1));
  printf("\nName Length: %d",record.nameLength);
  fread(nameString,sizeof(char),record.nameLength,fp);
  nameString[record.nameLength] = '\0';
  printf("\nName: %s",nameString);
  printf("\n");

  fclose(fp);

  return 0;
}

答案 1 :(得分:0)

我想添加我的输入....因为你将内存结构转储到磁盘,用于保存数据的指针地址在转储之前肯定是有效的,但是当从它们读取时,指针地址可能无效....这可以解释为什么字符指针没有显示名称......

答案 2 :(得分:0)

首先,一个挑剔:你永远不需要sizeof(char) - 根据定义它总是1。

至于空白名称输出:你可能需要在%s之后换行才能刷新输出吗?当你把它留下来时,我已经看到了奇怪的行为,而你没有说明你正在使用哪个平台。如果平台的printf()被奇怪地实现,你可以打印和刷新格式字符串,但是当程序退出时,名称本身会卡在C库的缓冲区中。

我从不高兴阅读或编写二进制数据blob,如文件中的结构。意识到通过这样做,你承诺你的程序只会读取它在同一平台上写的 。您无法在64位主机上写入文件,并在16位微波炉控制器上读回文件。