在写入文件并在 c 中关闭文件后从文件中读回的问题

Problems with reading back from a file after writing to it and closing it in c

我正在尝试使用 fread 和 fwrite 来读取和写入与文件中的结构有关的数据。这是我的代码:

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

typedef struct book book;

struct book
{
char title[200];
char auth[200];
char publi[200];
int p_year;
int price;
int edition;
int isbn;
};

int main()
{
    int i;
    FILE* fp = fopen("this.dat","w");
    book * a = calloc(1000000,sizeof (book));

    srand(time(NULL));

    for(i=0;i<1000000;i++)
    {
        a[i].price = rand()%1000;
        a[i].p_year = 1500 + rand()%518;
        a[i].isbn = 10000+rand()%100000;
        a[i].edition = i%15;

        strcpy(a[i].title,"title");
        strcpy(a[i].auth,"author");
        strcpy(a[i].publi,"publication");
    }

    if((i=fwrite(a,sizeof(*a),1000000,fp))!= 1000000)
    {
        printf("ERROR - Only %d records written\n",i);
        printf("feof:%d\nferror:%d",feof(fp),ferror(fp));
        return EXIT_FAILURE;
    }

    if(ferror(fp))
    {
        printf("ERROR");
        return EXIT_FAILURE;
    }

    if(fclose(fp)!=0)
    {
        printf("ERROR while closing the stream");
        return EXIT_FAILURE;
    } 

    if((fp = fopen("this.dat","r")) == NULL)
    {
        printf("ERROR reopening");
        return EXIT_FAILURE;
    }

    if((i=fread(a,sizeof(book),100,fp))!=100)
    {
        printf("ERROR - Only %d records read\n",i);
        printf("feof:%d\nferror:%d",feof(fp),ferror(fp));
        return EXIT_FAILURE;
    }

    if(ferror(fp))
    {
        printf("~ERROR");
        return EXIT_FAILURE;
    }

    for(i=0;i<100;i++)
        printf("price:%d\nedition:%d\nisbn:%d\np_year:%d\n\n\n",a[i].price,a[i].edition,a[i].isbn,a[i].p_year);


    fclose(fp);
    return EXIT_SUCCESS;
    }

事情是偶尔会成功执行,但大多数时候不会。使用 fread 从文件中读回时出现错误。它最终每次读取可变数量的记录并且记录数量少于预期(即 100)。以下是程序执行失败的输出之一:

错误 - 仅读取了 25 条记录
feof:16
ferror:0

问题1:为什么写了25条以上的记录,eof只读了25条? (我尝试在重新打开文件后使用 rewind/fseek,但问题仍然存在。)

问题2:在这种情况下,a数组a[x-1]之后的数据在[=16时被篡改是否正常? =] (<100) 条记录被读取 ?即使成功读取100条记录,数据是否仍然被篡改超过a[99](我知道数据被篡改了,因为尝试打印超出 xth 元素的数组 a 的元素字段会导致不适当的值,例如价格 > 1000 或价格 <0 等等上)

当 reading/writing 为二进制结构时,您不应该以文本模式打开文件。

虽然它对 Linux/Unix 没有影响,但对 Windows 这会产生严重的后果。它使您的文件 non-shareable 介于 Windows 和 Linux 之间。

根据数据 LF <=> CR/LF 转换可以 corrupt/shift 数据(删除马车 return 或插入一个)

在 Windows 的文本模式下,每个 LF (ASCII 10) 字节在写入时被 CR+LF (13+10 ASCII) 字节替换(在读取时反转:13+10 => 10) .这 10 个字节可能会发生,例如将 1802 年(十六进制:0x70A)写入二进制时。

解决方法:使用二进制模式:

if((fp = fopen("this.dat","rb")) == NULL)

FILE* fp = fopen("this.dat","wb");

注意:在"text"模式下,指定块大小不起作用,因为大小取决于数据。这可能回答了您的第二个问题:最后读取的第 100 条记录已损坏,因为您读取的字节太少。我不确定细节,但由于 writing/reading 时系统 adds/removes 字节,块大小可能有问题。