C语言中二进制文件的读写

C语言中二进制文件的读写,c,C,这个问题以前被问过很多次,但我已经用各种方法尝试了几个小时,我不知道为什么这是错误的 我一直在使用fwrite()将C结构写入二进制文件,并尝试使用fread()读取它们。然而,在我从文件中读取之后,当我试图打印结果时,我在结构中得到的只是毫无意义的答案。我已经转储了二进制文件,它看起来很好,所以我不太确定出了什么问题。有人能帮忙吗?我在Ubuntu 16.0432位上运行所有这些 结构: typedef struct { char file_name[256]; int dat

这个问题以前被问过很多次,但我已经用各种方法尝试了几个小时,我不知道为什么这是错误的

我一直在使用
fwrite()
将C结构写入二进制文件,并尝试使用
fread()
读取它们。然而,在我从文件中读取之后,当我试图打印结果时,我在结构中得到的只是毫无意义的答案。我已经转储了二进制文件,它看起来很好,所以我不太确定出了什么问题。有人能帮忙吗?我在Ubuntu 16.0432位上运行所有这些

结构:

typedef struct
{
    char file_name[256];
    int data_length;
} FileInfo;
从文件中读取:

void displayInformation(FILE *file) {
  FileInfo fileInfo;

  if (fread(&fileInfo, sizeof(FileInfo), 1, file) < 0)
    printf("something went wrong with reading the file\n");

  printf("FileInfo: %s\n", fileInfo.file_name);
  printf("FileInfo: %d\n", fileInfo.data_length);
}
文件的hexdump:

hexdump ./bin/example.bin

0000000 2f2e 6962 2f6e 7865 6d61 6c70 0065 0000
0000010 0000 0000 0000 0000 0000 0000 0000 0000
*
0000100 0034 0000 0001 0000 003e 0000 0000 0000
0000110 f362 4e1d 86c3 0e91 49c2 8e6c 6df6 d1bb
0000120 0002 0000 c437 3eeb 0003 0000 0792 0000
0000130 0004 0000 0000 0000
0000138
谢谢


编辑:我明白了,这是因为我没有从正确的目录中读取文件。谢谢大家的帮助!这真的很有用。

以下是我第一次解决这个问题的方法:

typedef struct
{
  // data_length should come first because it's not an arbitrary length and needs
  // to be aligned on a 4-byte boundary. This avoids ugly padding issues.
  int data_length;
  char file_name[256];
} FileInfo;

size_t writeFileInfo(FILE* f, FileInfo* fi) {
  return fwrite((void*)&fi->data_length, sizeof(int), 1, f) &&
    fwrite((void*)&fi->file_name, 1, fi->data_length, f);
}

size_t readFileInfo(FILE* f, FileInfo* fi) {
  size_t rv = 0;

  rv += fread((void*)&fi->data_length, sizeof(int), 1, f);
  rv += fread((void*)&fi->file_name, 1, fi->data_length, f);

  // Don't forget to NULL-terminate this string
  fi->file_name[fi->data_length] = 0;

  return rv;
}
这两个函数将读写操作分解为自包含的代码块,但它们可以很容易地分别合并为另一个读写函数的一部分

这里的诀窍是将标题中的可变长度字段写成长度+字符串对。较旧的文件格式将为这些字段使用8位或16位值,以避免文件膨胀,但两个额外的字节可能并不是世界末日。如果您觉得有必要,可以通过将长度字段切换到
uint16\u t
来修剪这些字段

下面是一个快速演示:

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

void testWrite(char* path) {
  FILE* f = fopen(path, "w");

  FileInfo example;

  strcpy(example.file_name, "example.txt");
  example.data_length = strlen(example.file_name);

  writeFileInfo(f, &example);

  fclose(f);
}

void testRead(char* path) {
  FILE* f = fopen(path, "r");

  FileInfo example;

  readFileInfo(f, &example);

  printf("Read: %d / %s\n", example.data_length, example.file_name);

  fclose(f);
}

int main(int argc, char** argv) {
  char* testDump = "dump.bin";

  testWrite(testDump);
  testRead(testDump);

  return 0;
}
#包括
#包括
void testWrite(字符*路径){
文件*f=fopen(路径,“w”);
文件信息示例;
strcpy(example.file_name,“example.txt”);
example.data\u length=strlen(example.file\u name);
writeFileInfo(f和示例);
fclose(f);
}
void testRead(字符*路径){
文件*f=fopen(路径,“r”);
文件信息示例;
readFileInfo(f和示例);
printf(“读取:%d/%s\n”,example.data\u长度,example.file\u名称);
fclose(f);
}
int main(int argc,字符**argv){
char*testDump=“dump.bin”;
testWrite(testDump);
testRead(testDump);
返回0;
}
您应该得到一个包含正确内容的简单二进制文件。在读入原始缓冲区时,请密切注意正确的NULL终止字符串。C总是一个微小的错误,从一个巨大的缓冲区溢出错误


您需要去掉固定长度的字符缓冲区,并使用类似于
malloc()
的内容来读取大小字段指定的大小。但要小心可能存在的巨大价值。单位翻转损坏错误可能会诱使您的程序无缘无故地分配2GB内存。

以下是我第一次解决此问题的方法:

typedef struct
{
  // data_length should come first because it's not an arbitrary length and needs
  // to be aligned on a 4-byte boundary. This avoids ugly padding issues.
  int data_length;
  char file_name[256];
} FileInfo;

size_t writeFileInfo(FILE* f, FileInfo* fi) {
  return fwrite((void*)&fi->data_length, sizeof(int), 1, f) &&
    fwrite((void*)&fi->file_name, 1, fi->data_length, f);
}

size_t readFileInfo(FILE* f, FileInfo* fi) {
  size_t rv = 0;

  rv += fread((void*)&fi->data_length, sizeof(int), 1, f);
  rv += fread((void*)&fi->file_name, 1, fi->data_length, f);

  // Don't forget to NULL-terminate this string
  fi->file_name[fi->data_length] = 0;

  return rv;
}
这两个函数将读写操作分解为自包含的代码块,但它们可以很容易地分别合并为另一个读写函数的一部分

这里的诀窍是将标题中的可变长度字段写成长度+字符串对。较旧的文件格式将为这些字段使用8位或16位值,以避免文件膨胀,但两个额外的字节可能并不是世界末日。如果您觉得有必要,可以通过将长度字段切换到
uint16\u t
来修剪这些字段

下面是一个快速演示:

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

void testWrite(char* path) {
  FILE* f = fopen(path, "w");

  FileInfo example;

  strcpy(example.file_name, "example.txt");
  example.data_length = strlen(example.file_name);

  writeFileInfo(f, &example);

  fclose(f);
}

void testRead(char* path) {
  FILE* f = fopen(path, "r");

  FileInfo example;

  readFileInfo(f, &example);

  printf("Read: %d / %s\n", example.data_length, example.file_name);

  fclose(f);
}

int main(int argc, char** argv) {
  char* testDump = "dump.bin";

  testWrite(testDump);
  testRead(testDump);

  return 0;
}
#包括
#包括
void testWrite(字符*路径){
文件*f=fopen(路径,“w”);
文件信息示例;
strcpy(example.file_name,“example.txt”);
example.data\u length=strlen(example.file\u name);
writeFileInfo(f和示例);
fclose(f);
}
void testRead(字符*路径){
文件*f=fopen(路径,“r”);
文件信息示例;
readFileInfo(f和示例);
printf(“读取:%d/%s\n”,example.data\u长度,example.file\u名称);
fclose(f);
}
int main(int argc,字符**argv){
char*testDump=“dump.bin”;
testWrite(testDump);
testRead(testDump);
返回0;
}
您应该得到一个包含正确内容的简单二进制文件。在读入原始缓冲区时,请密切注意正确的NULL终止字符串。C总是一个微小的错误,从一个巨大的缓冲区溢出错误


您需要去掉固定长度的字符缓冲区,并使用类似于
malloc()
的内容来读取大小字段指定的大小。但要小心可能存在的巨大价值。一个位翻转损坏错误可能会无缘无故地欺骗您的程序分配2GB内存。

这是一个非常简单的错误-因为我根本没有读取文件。将if语句更改为
这是一个非常简单的错误-因为我根本没有读取文件。将if语句更改为
什么是
FileInfo
?它包含指针吗?您应该编辑您的问题,以包含有关该问题的一些信息,因为它似乎是您问题的根源。很抱歉,我已经更新了该问题,并且在问号中包含了二进制文件。按原样将该内容粉碎到文件中看起来相当浪费,因为其中有一个很大的,可能大部分是空字符串缓冲区。在编写二进制数据时,请考虑使用<代码> INT/COD>长度字段作为读取文件时的提示,以了解要读取多少字节。谢谢。这会导致我现在的问题吗?什么是
FileInfo
?它包含指针吗?您应该编辑您的问题,以包含有关该问题的一些信息,因为它似乎是您问题的根源。很抱歉,我已经更新了该问题,并且在问号中包含了二进制文件。按原样将该内容粉碎到文件中看起来相当浪费,因为其中有一个很大的,可能大部分是空字符串缓冲区。在编写二进制数据时,请考虑使用<代码> INT/COD>长度字段作为读取文件时的提示,以了解要读取多少字节。谢谢。那会导致我的职业生涯失败吗
if (fread(&fileInfo, sizeof(FileInfo), 1, file) <= 0)
    printf("something went wrong with reading the file\n");