fread和fwrite函数有问题

时间:2018-08-10 21:13:58

标签: c struct fwrite fread

我有问题。

我正在尝试创建一个文件,然后再次读取它,将值保存在新结构中。但是当我尝试打印这些值时,我只是在7个值之后得到garbaje。

我在做什么错?

或者可能存在fwrite限制

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

struct estructura_salida
{
    int num_art;
    int exist;
};

int main (void)
{
    fflush(stdin);

    int i,j;
    long reg;

    struct estructura_salida listado[100];
    struct estructura_salida ventas[100];

    struct estructura_salida listadol[100];
    struct estructura_salida ventasl[100];

    for(i=0;i<100;i++)
    {
        listado[i].num_art = i+1;
        listado[i].exist = i+20;    
        ventas[i].num_art = i+1;
        ventas[i].exist = i+10; 
    }

    printf("\ncargados\n");

    for(i=0;i<100;i++)
    {
        printf("\n%i\t%i\t%i",listado[i].num_art,listado[i].exist,ventas[i].exist);
    }   

    FILE *fp1;  
    FILE *fp2;  
    fp1 = fopen("C://stock.dbf","wt");  
    fp2 = fopen("C://ventas.dbf","wt"); 


    fwrite(listado,sizeof(struct estructura_salida),200,fp1);
    fwrite(ventas,sizeof(struct estructura_salida),200,fp2);

    fclose(fp1);
    fclose(fp2);


    printf("\nleyendo el archivo");

    fp1 = fopen("C://stock.dbf","rt");  
    fp2 = fopen("C://ventas.dbf","rt");     

    while(!feof(fp1))
    {
        fread(listadol,sizeof(listadol),1,fp1); 
    }

    while(!feof(fp2))
    {
        fread(ventasl,sizeof(ventasl),1,fp2);   
    }

    fclose(fp1);    
    fclose(fp2);

    printf("\narchivo leido\n");

    for(i=0;i<100;i++)
    {
        printf("\n%i\t%i\t%i",listadol[i].num_art,listadol[i].exist,ventasl[i].exist);
    }   

    return 0;
}

这是控制台的外观,我刚得到garbaje。 console

谢谢!

2 个答案:

答案 0 :(得分:1)

诊断

我相信几乎可以肯定您正在Windows系统上工作,因为您在"wt"模式下使用了fopen()t无法被C标准或大多数Unix系统识别。而且还因为您used fflush(stdin)在非Windows系统上基本上没有意义,但被定义为在Windows系统上执行或多或少有用的任务。

您的主要问题是您使用"wt"打开一个文本文件进行写入,但是当您使用fwrite()时,您正在将二进制数据写入一个文本文件。这意味着包含10或13的条目可能会引起混乱。

使用"wb"(和"rb"阅读时)。 C标准支持此功能,表示您正在执行二进制I / O,而不是文本I / O,并防止I / O系统对数据造成严重破坏。

当您只有包含100条记录的数组(正如R Sahu在其answer中指出的那样)时,您也在写200条记录-这也不是幸福的秘诀。

您使用while (!feof(fp1))的循环是错误的;使用while (!feof(file)) is always wrong。您将继续阅读相同的元素-listadol[0]ventasl[0],因为您只需将数组名称传递给fread()。您可以通过每个文件一次fread()操作来读回所有记录,或者您需要正确索引数组(例如,传递&listadol[i])。

严格来说,您应该验证fopen()调用是否成功。可以说,您应该对fread()fwrite()调用执行相同的操作。超级狂热者会检查fclose()呼叫。如果数据文件至关重要,则应这样做,以防磁盘上没有足够的空间,或者发生其他根本错误的事情。

处方

将更改汇总在一起,并使用NUM_ENTRIES来标识条目数(为了输出的紧凑性,将其从100更改为10),我得到:

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

struct estructura_salida
{
    int num_art;
    int exist;
};

enum { NUM_ENTRIES = 10 };

int main(void)
{
    struct estructura_salida listado[NUM_ENTRIES];
    struct estructura_salida ventas[NUM_ENTRIES];

    struct estructura_salida listadol[NUM_ENTRIES];
    struct estructura_salida ventasl[NUM_ENTRIES];

    for (int i = 0; i < NUM_ENTRIES; i++)
    {
        listado[i].num_art = i + 1;
        listado[i].exist = i + 20;
        ventas[i].num_art = i + 1;
        ventas[i].exist = i + 10;
    }

    printf("\ncargados\n");

    for (int i = 0; i < NUM_ENTRIES; i++)
    {
        printf("%i\t%i\t%i\n", listado[i].num_art, listado[i].exist, ventas[i].exist);
    }

    const char name1[] = "stock.dbf";
    const char name2[] = "ventas.dbf";
    FILE *fp1 = fopen(name1, "wb");
    FILE *fp2 = fopen(name2, "wb");
    if (fp1 == NULL)
    {
        fprintf(stderr, "Failed to open file %s for reading\n", name1);
        exit(EXIT_FAILURE);
    }
    if (fp2 == NULL)
    {
        fprintf(stderr, "Failed to open file %s for reading\n", name2);
        exit(EXIT_FAILURE);
    }

    fwrite(listado, sizeof(struct estructura_salida), NUM_ENTRIES, fp1);
    fwrite(ventas, sizeof(struct estructura_salida), NUM_ENTRIES, fp2);

    fclose(fp1);
    fclose(fp2);

    printf("\nleyendo el archivo");

    fp1 = fopen(name1, "rb");
    fp2 = fopen(name2, "rb");
    if (fp1 == NULL)
    {
        fprintf(stderr, "Failed to open file %s for reading\n", name1);
        exit(EXIT_FAILURE);
    }
    if (fp2 == NULL)
    {
        fprintf(stderr, "Failed to open file %s for reading\n", name2);
        exit(EXIT_FAILURE);
    }

    int n;
    for (n = 0; fread(&listadol[n], sizeof(listadol[n]), 1, fp1) == 1; n++)
        ;

    int m;
    for (m = 0; fread(&ventasl[m], sizeof(ventasl[m]), 1, fp2) == 1; m++)
        ;

    fclose(fp1);
    fclose(fp2);

    printf("\narchivo leido\n");
    if (n != m)
    {
        fprintf(stderr, "Read different numbers of records (%d from %s, %d from %s)\n",
                n, name1, m, name2);
        exit(EXIT_FAILURE);
    }

    for (int i = 0; i < n; i++)
    {
        printf("%i\t%i\t%i\n", listadol[i].num_art, listadol[i].exist, ventasl[i].exist);
    }

    return 0;
}

最好使用一个功能来打开文件以检查失败并报告错误并退出,这是读者的一项练习。

输出是:

cargados
1   20  10
2   21  11
3   22  12
4   23  13
5   24  14
6   25  15
7   26  16
8   27  17
9   28  18
10  29  19

leyendo el archivo
archivo leido
1   20  10
2   21  11
3   22  12
4   23  13
5   24  14
6   25  15
7   26  16
8   27  17
9   28  18
10  29  19

一个十六进制转储程序显示两个数据文件包含您所期望的:

stock.dbf:
0x0000: 01 00 00 00 14 00 00 00 02 00 00 00 15 00 00 00   ................
0x0010: 03 00 00 00 16 00 00 00 04 00 00 00 17 00 00 00   ................
0x0020: 05 00 00 00 18 00 00 00 06 00 00 00 19 00 00 00   ................
0x0030: 07 00 00 00 1A 00 00 00 08 00 00 00 1B 00 00 00   ................
0x0040: 09 00 00 00 1C 00 00 00 0A 00 00 00 1D 00 00 00   ................
0x0050:
ventas.dbf:
0x0000: 01 00 00 00 0A 00 00 00 02 00 00 00 0B 00 00 00   ................
0x0010: 03 00 00 00 0C 00 00 00 04 00 00 00 0D 00 00 00   ................
0x0020: 05 00 00 00 0E 00 00 00 06 00 00 00 0F 00 00 00   ................
0x0030: 07 00 00 00 10 00 00 00 08 00 00 00 11 00 00 00   ................
0x0040: 09 00 00 00 12 00 00 00 0A 00 00 00 13 00 00 00   ................
0x0050:

除了奇数CR或LF外,没有其他可打印字符,因此右侧的信息并不能提供所有信息。 (使用GCC 8.2.0在运行macOS 10.13.6 High Sierra的Mac上进行了测试。)

答案 1 :(得分:1)

问题1

fwrite(listado,sizeof(struct estructura_salida),200,fp1);
fwrite(ventas,sizeof(struct estructura_salida),200,fp2);

您试图在只有100个对象的情况下写200个对象。这会导致未定义的行为。

问题2

使用while(!feof(fp1))是不正确的。参见Why is “while ( !feof (file) )” always wrong?

更改代码以将数据读取到:

   int n = fread(listadol, sizeof(listadol[0]), 100, fp1); 
   // Now you can be sure that n objects were successfully read.

问题3

使用fread / fwrite时,以二进制模式而不是文本模式打开文件。

fp1 = fopen("C://stock.dbf", "wb");  
fp2 = fopen("C://ventas.dbf", "wb"); 

fp1 = fopen("C://stock.dbf", "rb");  
fp2 = fopen("C://ventas.dbf", "rb");