C 读取二进制文件时,如何对每个结构字段分别使用fread()?

C 读取二进制文件时,如何对每个结构字段分别使用fread()?,c,struct,binaryfiles,C,Struct,Binaryfiles,在我的struct中,我得到了字段 struct records { short link; double gate; unsigned char bar; int rest; char rink; }; 在我的main()中 intmain(intargc,char*argv[]){ 结构记录记录记录; if(argcfread需要两个重要参数:指针和长度 您可以很容易地获得以下两种: struct records { short li

在我的
struct
中,我得到了字段

struct records {
    short link; 
    double gate; 
    unsigned char bar;
    int rest; 
    char rink; 
};
在我的
main()中

intmain(intargc,char*argv[]){
结构记录记录记录;

if(argcfread需要两个重要参数:指针和长度

您可以很容易地获得以下两种:

struct records {
    short link; 
    double gate; 
    unsigned char bar;
    int rest; 
    char rink; 
};

int main(int argc, char* argv[]){
    struct records rec;

    // ...

    FILE *fp=fopen(argv[1], "rb");

    // ...

    //use fread() for each field in struct separately.   

    while (!feof(fp))
    {
        if (fread(&rec.link, sizeof(rec.link), 1, fp) != 1
           || fread(&rec.gate, sizeof(rec.gate), 1, fp) != 1
           || // etc...
           )
        {
            // error !
        }
        // print the contents of rec, for example...
    }
    // ...
}

我迟到了,但这可能有用

您可以借助
offsetof()
函数来完成此操作

这里涉及到填充字节

sizeof(struct records)
在我的机器中是
32
字节(但不同机器的大小可能不同)

然而,
struct-record
变量的所有成员的组合大小仅为
sizeof(short)+sizeof(double)+sizeof(unsigned char)+sizeof(int)+sizeof(char)
在我的机器上应该是
16
字节(假设
short
double
unsigned char
int
char
分别占用2、8、1、4和1字节)

这是因为有一种称为“填充字节”的东西。你可以阅读它。这样做是为了让处理器更容易处理

所以根据这些尺寸,

结构记录
如下

---------------------------------------------------------------- | link(2) | 6 bytes | ---------------------------------------------------------------- | gate (8) | ---------------------------------------------------------------- | bar(1) | 3 bytes | rest(4) | ---------------------------------------------------------------- | rink(1) | 7 bytes | ---------------------------------------------------------------- 这张照片

link: 0
gate: 8
bar: 16
rest: 20
rink: 24
您可以使用此方法查找机器中结构构件的包装方式

现在需要做的是读取所需的数据,同时忽略填充字节

让我们创建一个结构变量
a

fread(&a.link, sizeof(a.link), 1, fp);
fseek(fp, 6, 1); //move the file pointer by 6 bytes from current position to avoid the padding bytes

fread(&a.gate, sizeof(a.gate), 1, fp);
fread(&a.bar, sizeof(a.bar), 1, fp);
fseek(fp, 3, 1); //move the file pointer to avoid the 3 bytes

fread(&a.rest, sizeof(a.rest), 1, fp);
fread(&a.rink, sizeof(a.rink), 1, fp);
现在您可以使用
a
中的值

fread(&a.link, sizeof(a.link), 1, fp);
fseek(fp, 6, 1); //move the file pointer by 6 bytes from current position to avoid the padding bytes

fread(&a.gate, sizeof(a.gate), 1, fp);
fread(&a.bar, sizeof(a.bar), 1, fp);
fseek(fp, 3, 1); //move the file pointer to avoid the 3 bytes

fread(&a.rest, sizeof(a.rest), 1, fp);
fread(&a.rink, sizeof(a.rink), 1, fp);



当你问上一个问题时,我不知道怎么做。但是我读了一些书,找到了一个方法。因为你发布了一个单独的问题,我想最好在这里发布一个答案。

你是如何编写文件的?文件可以在不同的机器上写入和读取吗?@taskino或者它是针对一个uni类的,所以老师写了它。我会的假设是他写的,所以它可以在所有机器上运行。你不能在不知道字段的写入顺序的情况下读取单个字段。此外,如果不特别注意二进制文件,则可能无法移植(google for little big endian)。要正确读取这些字段,首先需要知道它们是如何写入的。请查看
stddef.h
中的
offsetof
。(不,将结构读写成二进制只适用于给定的编译器,您可以在您的计算机上执行,但不要将数据文件交给其他人,并期望他们能够使用不同的编译器编译您的代码并读取您的文件,结构中的填充可能因编译器而异)这就是为什么你应该在写之前序列化数据,然后在读之后反序列化。对于你的作业,忽略它,但要知道你必须在现实世界中序列化,就像你通过网络发送数据一样。谢谢,我使用了这种语法并使其正常工作。我使用了
fread(&rec.link,sizeof(rec.link),1,fp)
每个字段,然后是
printf
所有字段。我现在有一个新问题,那就是如何在打印后继续重写结构?这样我就可以继续打印新值?有点像一个循环,存储结构值,打印它们,然后重写值,然后再次打印?我是否应该为此发布一个新问题?你可以创建一个列表来存储您读取的新记录,或者将它们保存在一个动态数组中。您介意详细说明动态数组吗?如果可能,创建一个列表来存储新记录是什么意思?谢谢如果您只想一次打印一条记录,您可以简单地循环整个文件,就像按记录读取一样…使用您的
while(!feof(fp))
和其他各种
虽然
eof
打印数据,但总是重复最后一行。因此它以最后一行结束每个输出两次。为什么要这样做?我发现它很奇怪,因为它不是每一行都输出两次,只是最后一行。@MichaëlRoy如果改用
%zu
,它会正确吗?对不起.我看错了。你说的偏移量与原来的问题无关。@MichaëlRoy我从中得到了这个。这个例子打印了这样的偏移量。只是与问题无关。
fread(&a.link, sizeof(a.link), 1, fp);
fseek(fp, 6, 1); //move the file pointer by 6 bytes from current position to avoid the padding bytes

fread(&a.gate, sizeof(a.gate), 1, fp);
fread(&a.bar, sizeof(a.bar), 1, fp);
fseek(fp, 3, 1); //move the file pointer to avoid the 3 bytes

fread(&a.rest, sizeof(a.rest), 1, fp);
fread(&a.rink, sizeof(a.rink), 1, fp);