fread 和 fwrite 函数有问题
Having an issue with fread and fwrite function
我有问题。
我正在尝试创建一个文件,然后再次读取它,将值保存在一个新结构中。但是当我尝试打印这些值时,我只在 7 个值之后得到 garbaje。
我做错了什么?
或者可能存在写入限制
#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
谢谢!!
诊断
我相信您几乎肯定在 Windows 系统上工作,因为您在 fopen()
模式下使用了 "wt"
。 t
不被 C 标准或大多数 Unix 系统识别。也因为你 used fflush(stdin)
这在非 Windows 系统上基本上没有意义,但被定义为在 Windows 系统上完成或多或少有用的任务。
您的主要问题是您使用 "wt"
打开文本文件进行写入,但是当您使用 fwrite()
时,您正在将二进制数据写入文本文件。这意味着包含 10 或 13 的条目可能会导致混乱。
使用"wb"
(阅读时使用"rb"
)。这是 C 标准支持的,表示您正在执行二进制 I/O,而不是文本 I/O,并防止 I/O 系统对您的数据造成严重破坏。
当您只有包含 100 条记录的数组时,您也在写入 200 条记录(正如 R Sahu in their 所指出的)——这也不是幸福的秘诀。
您使用 while (!feof(fp1))
的循环是错误的;使用 while (!feof(file))
is always wrong。您一直在读取相同的元素 — listadol[0]
和 ventasl[0]
,因为您只是将数组名称传递给 fread()
。您可以在每个文件的一个 fread()
操作中读回所有记录,或者您需要正确索引数组(例如传递 &listadol[i]
)。
严格来说,您应该验证 fopen()
调用(尤其是)是否成功。可以说,您应该对 fread()
和 fwrite()
调用执行相同的操作。超级狂热者会检查 fclose()
调用。如果数据文件很重要,你应该这样做,以防万一 space 磁盘上没有足够的空间,或者出现其他根本错误。
处方
将更改放在一起,并使用 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;
}
最好使用一个函数来打开检查失败并报告错误并退出的文件 — reader.
的练习
输出是:
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 之外,没有任何可打印的字符,所以右边的信息不是那么有用。 (在 Mac 运行 macOS 10.13.6 High Sierra 上测试,使用 GCC 8.2.0。)
问题 1
fwrite(listado,sizeof(struct estructura_salida),200,fp1);
fwrite(ventas,sizeof(struct estructura_salida),200,fp2);
您试图写入 200 个对象,而您只有 100 个。这会导致未定义的行为。
问题 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");
我有问题。
我正在尝试创建一个文件,然后再次读取它,将值保存在一个新结构中。但是当我尝试打印这些值时,我只在 7 个值之后得到 garbaje。
我做错了什么?
或者可能存在写入限制
#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
谢谢!!
诊断
我相信您几乎肯定在 Windows 系统上工作,因为您在 fopen()
模式下使用了 "wt"
。 t
不被 C 标准或大多数 Unix 系统识别。也因为你 used fflush(stdin)
这在非 Windows 系统上基本上没有意义,但被定义为在 Windows 系统上完成或多或少有用的任务。
您的主要问题是您使用 "wt"
打开文本文件进行写入,但是当您使用 fwrite()
时,您正在将二进制数据写入文本文件。这意味着包含 10 或 13 的条目可能会导致混乱。
使用"wb"
(阅读时使用"rb"
)。这是 C 标准支持的,表示您正在执行二进制 I/O,而不是文本 I/O,并防止 I/O 系统对您的数据造成严重破坏。
当您只有包含 100 条记录的数组时,您也在写入 200 条记录(正如 R Sahu in their
您使用 while (!feof(fp1))
的循环是错误的;使用 while (!feof(file))
is always wrong。您一直在读取相同的元素 — listadol[0]
和 ventasl[0]
,因为您只是将数组名称传递给 fread()
。您可以在每个文件的一个 fread()
操作中读回所有记录,或者您需要正确索引数组(例如传递 &listadol[i]
)。
严格来说,您应该验证 fopen()
调用(尤其是)是否成功。可以说,您应该对 fread()
和 fwrite()
调用执行相同的操作。超级狂热者会检查 fclose()
调用。如果数据文件很重要,你应该这样做,以防万一 space 磁盘上没有足够的空间,或者出现其他根本错误。
处方
将更改放在一起,并使用 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;
}
最好使用一个函数来打开检查失败并报告错误并退出的文件 — reader.
的练习输出是:
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 之外,没有任何可打印的字符,所以右边的信息不是那么有用。 (在 Mac 运行 macOS 10.13.6 High Sierra 上测试,使用 GCC 8.2.0。)
问题 1
fwrite(listado,sizeof(struct estructura_salida),200,fp1);
fwrite(ventas,sizeof(struct estructura_salida),200,fp2);
您试图写入 200 个对象,而您只有 100 个。这会导致未定义的行为。
问题 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");