Scotty~~ 2023-10-03 22:22 采纳率: 66.7%
浏览 7
已结题

关于#c语言文件读取二进制文件信息##结构体#的问题,请各位专家解答!

C语言二进制文件读取结构体变量时多读取一个结构体的长度

最近使用C语言的文件写入和读取时发现有个问题。
首先我创建一个结构体数组,空间为5,我先里面输入2个结构体变量的值,然后输出出来(看输出结果是对的),同时将这2个结构体变量用fwrite写入到一个.dat文件中(这个文件是空的)。

然后我再打开这个.dat文件,使用fseek和ftell搭配使用,检测这个.dat文件中有多少个结构体数据,结果为2,这与预期是一致的。但是当我使用feof()函数作为判断是否读取到文件末尾时出现问题,程序会读取到3个结构体数据,前2个结构体数据是与我输入的数据一致,但是第3个结构体数据是一串乱码,这乱码包含了一些我的电脑的信息,如用户名,program之类的东西。

这个文件数据长度测量与文件是否读取到末尾为何会出现这种情况?我测试了几个写好的程序,都出现这种情况,是与系统配置之类的有关系吗?


```c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct st
{
    char str1[20];
    double num;
    char str2[20];
}ST;


//测试程序:首先应该往二进制文件中写入2个结构体变量的值
//然后再从该二进制文件中读取所有的结构体变量的值,看是否在文件结尾上多一个不知名的东西
int main()
{
    void write_data(ST*);
    void show_data(ST*);

    //创建一个结构体数组,空间为5
    ST test[5];
    //write_data(test);  //写入数据后可以将这项注释掉
    show_data(test);  //这个是用来输出数据的

    return 0;
    
}

void write_data(ST* t)
{
    //只写入两个结构体变量的值

    int i;
    FILE* fp;
    if((fp=fopen("C:\\Users\\97692\\Desktop\\test\\test.dat","wb"))==NULL)
    printf("can not open this file"),exit(0);

    for(i=0;i<2;i++)
    {
        printf("请输入字符串1、双精度浮点数和字符串2:\n");
        scanf("%s",t[i].str1);
        scanf("%lf",&t[i].num);
        scanf("%s",t[i].str2);
        fwrite(&t[i],sizeof(ST),1,fp);
        printf("%s %lf %s\n\n",t[i].str1,t[i].num,t[i].str2);

    }

    fclose(fp);
}

void show_data(ST* t)
{
    FILE* fp;
    int i=0,n;
    long leng;
    if((fp=fopen("C:\\Users\\97692\\Desktop\\test\\test.dat","rb"))==NULL)
        printf("can not open this file"),exit(0);

    fseek(fp,0L,SEEK_END);  //将文件位置标记移动到结尾
    leng=ftell(fp);     
    printf("\n\n文件结点数是%I64d\n\n\n",n=leng/sizeof(ST)); //输出该文件中结构体结点的个数
    rewind(fp); //文件位置标记移动到开头

    while(!feof(fp))
    {
        fread(&t[i],sizeof(ST),1,fp);
        printf("结点%d的数据是: %s  %lf  %s\n",i+1,t[i].str1,t[i].num,t[i].str2);
        i++;
![img](https://img-mid.csdnimg.cn/release/static/image/mid/ask/095908243696174.jpg "#left")

        
    }
}

```

  • 写回答

2条回答 默认 最新

  • ChatGPTᴼᴾᴱᴺᴬᴵ 2023-10-03 22:29
    关注

    所有内容均由人工智能模型输出,其内容的准确性和完整性无法保证,不代表我的态度或观点。

    该回答引用ChatGPT-3.5,仅为您提供参考,不保证完全正确
    问题出现的原因是在 show_data 函数中使用了 feof() 函数来判断文件是否读取到末尾,但 feof() 函数并不可靠,它只能在已经发生文件结束符(EOF)标志时返回 true,而不能在文件结束之前提前告诉你文件的确已经结束。因此,它在这种情况下不适用。


    解决这个问题的方法是不依赖 feof() 来判断文件是否结束,而是使用返回值 fread 来检查读取的字节数。当 fread 返回值小于期望读取的字节数时,就说明已经到达了文件末尾。下面是修正后的 show_data 函数:

    void show_data(ST* t)
    {
        FILE* fp;
        int i = 0, n;
        if ((fp = fopen("C:\\Users\\97692\\Desktop\\test\\test.dat", "rb")) == NULL)
            printf("can not open this file"), exit(0);
    
        fseek(fp, 0L, SEEK_END);  //将文件位置标记移动到结尾
        long leng = ftell(fp);
        printf("\n\n文件结点数是%I64d\n\n\n", n = leng / sizeof(ST)); //输出该文件中结构体结点的个数
        rewind(fp); //文件位置标记移动到开头
    
        while (i < n)
        {
            if (fread(&t[i], sizeof(ST), 1, fp) != 1)
            {
                printf("Error reading data from file\n");
                break;
            }
            printf("结点%d的数据是: %s  %lf  %s\n", i + 1, t[i].str1, t[i].num, t[i].str2);
            i++;
        }
    
        fclose(fp);
    }
    

    在这个修正后的代码中,我们在 fread 函数后检查了返回值是否等于1,如果不等于1,就说明文件已经结束,不再继续读取。这样就可以避免多读取一个结构体的长度,并且能够正确地处理文件末尾的情况。


    该回答引用NewBing,仅为您提供参考,不保证完全正确
    根据我找到的资料¹²³,C语言读取二进制文件中的结构体变量时,可能会出现以下几种原因导致多出一个乱码的情况:

    • 文件的打开模式不正确。如果要读写二进制文件,应该使用"rb"或"wb"等模式,而不是"r"或"w"等模式,否则可能会导致数据的损坏或解析错误¹³。
    • 文件的读取方式不正确。如果要判断文件是否读取到末尾,应该使用fread函数的返回值,而不是feof函数。因为feof函数只有在尝试读取文件末尾之后才会返回真值,而不是在读取到文件末尾时就返回真值。所以如果使用feof函数作为循环条件,可能会多读取一次文件,导致乱码²⁴。
    • 文件的写入方式不正确。如果要写入二进制文件中的结构体变量,应该使用fwrite函数,并且保证结构体中没有指针类型的成员。否则可能会导致指针类型的成员指向的数据无法正确保存或恢复¹⁵。

    综上所述,您可以尝试以下几个方法来解决您的问题:

    • 检查您的文件打开模式是否正确,如果不正确,请修改为二进制模式。
    • 检查您的文件读取方式是否正确,如果不正确,请修改为使用fread函数的返回值作为循环条件。
    • 检查您的文件写入方式是否正确,如果不正确,请修改为使用fwrite函数,并且保证结构体中没有指针类型的成员。

    源: 与必应的对话, 2023/10/3
    (1) C 文件读写 | 菜鸟教程. https://www.runoob.com/cprogramming/c-file-io.html.
    (2) 【C 语言】文件操作 ( 将结构体写出到文件中并读取结构体数据 | 将结构体数组写出到文件中并读取结构体数组数据 ). https://blog.csdn.net/shulianghan/article/details/121389427.
    (3) C语言结构体-结构的文件读写fread()、fwrite()以及读写文件乱码_c语言fread读入结构体-CSDN博客. https://blog.csdn.net/Peterwatwec/article/details/104484282.
    (4) 把结构体存入文本中出现乱码-CSDN社区. https://bbs.csdn.net/topics/390377443.
    (5) C / C++ 读取文件出现乱码解决方法 | 输出到文件出现乱码_c++乱码-CSDN博客. https://blog.csdn.net/qq_36667170/article/details/79620611.
    (6) C 文件读写 | 菜鸟教程. https://www.runoob.com/cprogramming/c-file-io.html.
    (7) 【C 语言】文件操作 ( 将结构体写出到文件中并读取结构体数据 | 将结构体数组写出到文件中并读取结构体数组数据 ). https://blog.csdn.net/shulianghan/article/details/121389427.
    (8) C语言结构体-结构的文件读写fread()、fwrite()以及读写文件乱码_c语言fread读入结构体-CSDN博客. https://blog.csdn.net/Peterwatwec/article/details/104484282.
    (9) 把结构体存入文本中出现乱码-CSDN社区. https://bbs.csdn.net/topics/390377443.
    (10) C / C++ 读取文件出现乱码解决方法 | 输出到文件出现乱码_c++乱码-CSDN博客. https://blog.csdn.net/qq_36667170/article/details/79620611.


    该回答引用文心一言,仅为您提供参考,不保证完全正确
    你的问题在于使用feof()函数判断文件是否读取到末尾。feof()函数是在读取操作执行之后才会被设置,这意味着在最后一次读取操作后,即使已经读到文件末尾,feof()函数仍然会返回0,也就是false,所以你的循环会多执行一次。


    在你的例子中,你的循环会尝试读取3个结构体,即使文件中只有2个。由于第三次读取会失败(因为已经读到文件末尾),所以读取的数据会是未定义的,这就是你看到乱码的原因。


    解决这个问题的一种方法是改变你的循环条件。而不是依赖feof()函数,你可以检查fread()函数返回的值。fread()函数会返回实际读取的元素个数,如果读取失败或者读到文件末尾,这个值会小于你传递给它的值。所以你可以这样改变你的循环:

    while(fread(&t[i],sizeof(ST),1,fp) == 1)
    {
        printf("结点%d的数据是: %s  %lf  %s\n",i+1,t[i].str1,t[i].num,t[i].str2);
        i++;
    }
    

    这样,你的循环会在fread()函数返回的值小于1时停止,这意味着它已经读取到文件末尾或者读取失败。注意,如果fread()函数读取失败,你可能还需要检查错误信息。


    另外,我注意到你在计算文件中结构体个数时使用了ftell()函数。这个方法在某些情况下可能不会正常工作,因为ftell()函数返回的是相对于文件开头的偏移量,而不是文件中的字节数。如果你的结构体中包含了指针或者其他非连续的数据类型,这个方法可能会返回错误的结果。为了准确的计算结构体个数,你可能需要记录你写入的结构体的数量。


    该回答引用讯飞星火,仅为您提供参考,不保证完全正确
    这个问题可能是由于在写入结构体数据时,没有按照二进制方式写入导致的。你可以尝试修改write_data函数中的fwrite部分,将结构体数据以二进制方式写入文件:

    fwrite(t, sizeof(ST), 2, fp);
    

    同时,你需要确保在读取结构体数据时,使用正确的偏移量。在你的代码中,你使用了sizeof(ST)作为偏移量,这可能会导致读取到额外的数据。你应该使用t数组的长度作为偏移量:

    while(!feof(fp))
    {
        fread(&t[i], sizeof(ST), 1, fp);
        printf("结点%d的数据是: %s  %lf  %s
    ", i+1, t[i].str1, t[i].num, t[i].str2);
        i++;
    }
    

    这样修改后,你的程序应该可以正确地读取结构体数据,而不会读取到额外的数据。


    该回答引用通义千问,仅为您提供参考,不保证完全正确
    你的问题在于你没有正确地处理结构体数组。当你使用fwrite写入结构体数组时,你只写入了前两个元素,但是当你使用fread读取结构体数组时,你没有指定要读取的元素数量,因此fread会读取整个文件。


    当你打开文件时,fseekftell用于测量文件的大小,但是当你使用fread读取文件时,fread会读取整个文件,包括你没有写入的额外数据。


    解决这个问题的方法是,当你使用fwrite写入结构体数组时,你应该指定要写入的元素数量,而不是只写入前两个元素。然后,在使用fread读取结构体数组时,你应该指定要读取的元素数量,与你写入的元素数量相同。这样,你就可以正确地处理结构体数组了。


    以下是修改后的代码:

    void write_data(ST* t)
    {
        // 写入两个结构体变量的值
        int i;
        FILE* fp;
        if((fp=fopen("C:\\Users\\97692\\Desktop\\test\\test.dat","wb"))==NULL)
        {
            printf("can not open this file"),exit(0);
        }
    
        for(i=0;i<2;i++)
        {
            printf("请输入字符串1、双精度浮点数和字符串2:\n");
            scanf("%s",t[i].str1);
            scanf("%lf",&t[i].num);
            scanf("%s",t[i].str2);
            fwrite(&t[i],sizeof(ST),1,fp);
            printf("%s %lf %s\n\n",t[i].str1,t[i].num,t[i].str2);
        }
    
        fclose(fp);
    }
    
    void show_data(ST* t)
    {
        FILE* fp;
        int i=0,n;
        long leng;
        if((fp=fopen("C:\\Users\\97692\\Desktop\\test\\test.dat","rb"))==NULL)
        {
            printf("can not open this file"),exit(0);
        }
    
        fseek(fp,0L,SEEK_END);  // 将文件位置标记移动到结尾
        leng=ftell(fp);     
        printf("\n\n文件结点数是%I64d\n\n\n",n=leng/sizeof(ST)); // 输出该文件中结构体结点的个数
        rewind(fp); // 文件位置标记移动到开头
    
        while(!feof(fp))
        {
            fread(&t[i],sizeof(ST),1,fp);
            printf("结点%d的数据是: %s  %lf  %s\n",i+1,t[i].str1,t[i].num,t[i].str2);
            i++;
        }
    
        fclose(fp);
    }
    

    这样,当你运行程序时,它应该只读取和显示你写入的两个结构体变量的数据,而不是读取和显示额外的数据。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 10月16日
  • 已采纳回答 10月8日
  • 创建了问题 10月3日

悬赏问题

  • ¥15 ogg dd trandata 报错
  • ¥15 高缺失率数据如何选择填充方式
  • ¥50 potsgresql15备份问题
  • ¥15 Mac系统vs code使用phpstudy如何配置debug来调试php
  • ¥15 目前主流的音乐软件,像网易云音乐,QQ音乐他们的前端和后台部分是用的什么技术实现的?求解!
  • ¥60 pb数据库修改与连接
  • ¥15 spss统计中二分类变量和有序变量的相关性分析可以用kendall相关分析吗?
  • ¥15 拟通过pc下指令到安卓系统,如果追求响应速度,尽可能无延迟,是不是用安卓模拟器会优于实体的安卓手机?如果是,可以快多少毫秒?
  • ¥20 神经网络Sequential name=sequential, built=False
  • ¥16 Qphython 用xlrd读取excel报错