之前已经多次询问过这个问题,但我已经用各种方法尝试了几个小时,我不知道为什么这是错误的。
我一直在使用fwrite()
将C结构编写到二进制文件中,并且我一直在尝试使用fread()
来读取它们。但是,在我从文件中读取之后,当我尝试打印出结果时,我得到的只是在我的结构中的无意义答案。我已经完成了二进制文件的转储,看起来很好,所以我不太确定是什么问题。有人可以帮忙吗?我在Ubuntu 16.04 32bit上运行所有这些。
STRUCT:
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);
}
写入档案:
void writeToFile() {
....
uint8_t outbuf[MAX_BUF_SIZE];
uint8_t *buf_ptr = outbuf;
strncpy(((FileHeader *)outbuf)->file_name, fileName, sizeof(((FileHeader *)outbuf)->file_name) - 1);
buf_ptr += sizeof(FileHeader);
....
fwrite(outbuf, sizeof(FileInfo) + ((FileInfo *)outbuf)->data_length, 1, outputFile);
}
文件的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
谢谢!
编辑:我想通了,这是因为我没有从正确的目录中读取文件。感谢大家的帮助!这真的很有用。答案 0 :(得分:2)
以下是我第一次接受问题的方法:
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_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;
}
你应该得到一个包含正确内容的简单二进制文件。在读入原始缓冲区时,请特别注意正确的NULL终止字符串。 C远离一个巨大的缓冲区溢出错误总是一个小错误。
你想要摆脱那个固定长度的字符缓冲区,并使用像malloc()
之类的东西来读取大小字段所指示的任何大小。但要注意可能的巨大价值。单个位翻转损坏错误可能会欺骗您的程序无缘无故地分配2GB内存。
答案 1 :(得分:0)
这是一个非常简单的错误 - 因为我根本没有读取文件。将if语句更改为<=0
有助于我追踪它。
自:
if (fread(&fileInfo, sizeof(FileInfo), 1, file) < 0)
printf("something went wrong with reading the file\n");
致:
if (fread(&fileInfo, sizeof(FileInfo), 1, file) <= 0)
printf("something went wrong with reading the file\n");