【问题标题】:Block I/O problems with reading float - C读取浮点数的阻塞 I/O 问题 - C
【发布时间】:2018-05-08 22:58:12
【问题描述】:

我最近一直在尝试编写一个文件写入程序,该程序可以保存零件编号、数量和零件价格的库存统计信息。在写入我的二进制文件时,我的 scanf 保存了我的价格,但是当我在下一个程序中读取它们时,它会出现大量无意义的数字,这不是我输入的。 编写程序的编译器:(* * 是用户输入)

This program stores a business inventory.
Please enter item data (part number, quantity, price): *2, 3, 1.6*
Please enter item data (part number, quantity, price): *3, 1, 5.3*
Please enter item data (part number, quantity, price): *0*
Thank you. Inventory stored in file inventory.txt

编写程序代码

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

int main(int argc, int argv[])
{
int pnum=1, quantity;
float price;
FILE *fp1;

fp1 = fopen("inventory.txt", "wb+");
if(fp1 == NULL)
{
    printf("Can't open!\n");
    exit(EXIT_FAILURE);
}

printf("This program stores a business inventory.\n");
while(pnum != 0)
{
printf("Please enter item data (part number, quantity, price): ");
scanf("%d, %d, %f", &pnum, &quantity, &price);
printf("%d, %d, %f", pnum, quantity, price);
fwrite(&pnum, sizeof(int), 1, fp1);// Is there a way to combine these 3 fwrites into 1?
fwrite(&quantity, sizeof(int), 1, fp1);
fwrite(&price, sizeof(float), 1, fp1);
}
printf("Thank you. Inventory stored in file inventory.txt");
fclose(fp1);
return 0;


}

带有读取程序的编译器(* * 是用户输入)

Below are the items in your inventory.
Part#    Quantity        Item Price
2         3                1070386381?
3         1                1084856730?
0?        1                1084856730?

读取程序代码

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

int main()
{
int pnum, quantity;
float price;
FILE *fp1 = fopen("inventory.txt", "rb");
if(fp1 == NULL)
{
    printf("Can't open!");
    exit(EXIT_FAILURE);
}
printf("Below are the items in your inventory.\n");

printf("Part#\tQuantity\t Item Price\n");
while (fread(&pnum, sizeof(int), 1, fp1) == 1)//Is there a way to combine these 3 freads into 1 line of code?
{
    printf("%5d\t", pnum);
}
while (fread(&quantity, sizeof(int), 1, fp1) == 1)
{
    printf("%8d\t", quantity);
}
while (fread(&price, sizeof(float), 1, fp1) == 1)
{
    printf("$");
    printf("%9.2f\n", price);

}
fclose(fp1);
return 0;

}

如您所见,scanf 是 scanf 并且必须与我的浮动有关,但我无法弄清楚如何修复它,因为没有 scanf 什么都不会保存到我的 inventory.txt 文件(我没有包含 .txt 文件,因为它是二进制文件),并且由于某种原因,当我输入 0 以中断循环时,它会将 0 保存在文件中。如果需要任何其他信息,我可以提供,但我想我已经提供了一切。感谢您的帮助,祝您编码愉快:)

【问题讨论】:

  • 我看不到“读取程序”如何生成该输出。第一个while 循环将消耗整个文件,并在一行上打印所有数字。
  • 我在读取的 printfs 中添加了 /t,因为打印时数量和价格结合在一起(没有空格),所以它看起来像 31070386381。你是说我的第一个'while' fread for pnum?跨度>
  • 这确定了问题,但另一方面修复它,我不太明白如何修复它,我对文件 IO 仍然有点绿色
  • 你按这个顺序写东西:pnum, qty, price, pnum, qty, price, pnum, qty, price。然后您按以下顺序阅读它们:pnum,pnum,pnum,pnum,pnum,pnum,pnum,pnum,pnum。您需要按照编写它们的顺序阅读它们。
  • “读取程序”需要一个包含三个freadwhile 循环。

标签: c file-io while-loop


【解决方案1】:
  • 零被插入到数组中,因为您的while 循环仅在fwrite 调用之后 中断。您可以使用break 我相信在scan 之后立即退出。
  • 要结合写入和读取,您可以使用结构,但请注意,由于padding,您可能应该从/到完全相同的结构进行序列化和反序列化。
  • suspect 认为你的freads 由于错误的写入/读取顺序或填充而产生奇怪的结果。尝试读取和写入结构,看看是否能解决您的问题。如果这不起作用,请尝试使用%x 打印浮点数的十六进制值。然后与预期结果进行比较。

考虑以下代码:

#include <stdio.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close


typedef struct
{
    float price;
    int pnum;
    int quantity;
} shoppingItem;


void writeToFile(FILE *fp) {    
    shoppingItem input1 = {1.1,2,3};
    shoppingItem input2 = {3.1412,42,666};
    fwrite(&input1, sizeof(shoppingItem), 1, fp);
    fwrite(&input2, sizeof(shoppingItem), 1, fp);
    printf("%f %d %d\n", input1.price, input1.pnum, input1.quantity);
    printf("%f %d %d\n", input2.price, input2.pnum, input2.quantity);
}

void readFromFile(FILE *fp) {
    shoppingItem output1 = {0.0,0,0};
    shoppingItem output2 = {0.0,0,0};
    fread(&output1, sizeof(shoppingItem), 1, fp);
    fread(&output2, sizeof(shoppingItem), 1, fp);
    printf("%f %d %d\n", output1.price, output1.pnum, output1.quantity);
    printf("%f %d %d\n", output2.price, output2.pnum, output2.quantity);
}

int main()
{
    FILE *fp = fopen("inventory.txt", "wb+");
    if(fp == NULL)
    {
        printf("Can't open!\n");
        return 1;
    }

    writeToFile(fp);
    rewind(fp);
    readFromFile(fp);

    if (fclose(fp) == 0) {
        printf("Done\n");
        return 0;
    } else {
        printf("Error on closing file\n");
        return 1;
    }
}

【讨论】:

  • 感谢您的意见;在实施它时,它运行良好,我还能够通过在非结构版本中实现一些评论想法来解决它,这也有效。事实证明,使用 &&s 将所有 freads 放入 1 while 循环修复了我声明的程序。感谢您的帮助!
  • 将原始结构写入文件并将其读回不是一个好主意,通常应该避免。在结构周围玩记忆就像在加油站玩打火机。
  • 这个问题演示了混合类型时不使用结构如何导致不正确的写入/读取顺序。在哪种情况下,例如使用结构会比单独写入多种不同类型的方法更糟糕?
  • 我同意这样在 C 中使用内存是完全不安全的(由于缺乏内置的抽象),因为在不同的系统上进行序列化和反序列化可能会产生不同的结果。跨度>
  • @AlexGordon 如果保留写入/读取顺序,则不会出错,因为文件始终以相同的方式写入 - 从头到尾。在实施类似的事情时应该谨慎,但这是可行的。正如您在我的回答中看到的那样,读数很好,但由于某种原因,它们没有从 IEEE-754 转换为十进制值。不应期望结构在内存中的对齐方式与它们在代码中的对齐方式相同,即使您使用了许多神奇的编译器标志。
【解决方案2】:

你在“阅读程序”中得到的奇怪值是完全有效的,但是......它们被编码为 IEEE-754 浮点值。如果将5.3 编码为IEEE-754,您将得到0x40a9999a,它等于1084856730,因此您的读数很好,但输出它却有问题。

将您的 printf 格式从 %9.2f 更改为 %f。如果这没有帮助,请尝试强制转换价格:fread((void*)(&amp;price), sizeof(float), 1, fp1)

为了将来 - 避免以这样的格式存储数据。如果您尝试在具有不同字节序的机器上读取该文件,结果将完全不同。

【讨论】:

  • 似乎确实在 OP 的机器上从文件中读取浮点值更改了编码。这要么是字节序问题,要么是 freadfwrite 的浮点数对浮点值使用不同的编码(不太可能因为它们对二进制数据进行操作)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-24
  • 2011-08-02
  • 2018-04-06
  • 1970-01-01
  • 2014-02-13
相关资源
最近更新 更多