【问题标题】:Should the binary output be the same as the ASCII input?二进制输出是否应该与 ASCII 输入相同?
【发布时间】:2021-06-25 23:54:58
【问题描述】:

我正在编写一个读取 ASCII 文件然后将其转换为二进制文件的程序,因为我认为这不是一项艰巨的任务,但了解背后发生的事情是......

据我所知,ASCII 文件只是人类可读的文本,所以如果我们想创建一个充满 ASCII 的新文件,一个带有 fputc() 的简单循环就足够了,而对于二进制文件 fwrite() 就足够了工作对吗?

所以我的问题是,一旦完成 ASCII 到二进制的转换,我应该在我的 .bin 文件中看到什么?应该填写完全相同的符号<88><88><88><88><88>?

代码:

/*
*  From "Practical C Programming 2nd Edition"
*  Exercise 14-4: Write a program that reads an ASCII file containing a list of numbers
*  and writes a binary file containing the same list. Write a program that goes the
*  other way so that you can check your work.
*
*/

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

const char *in_filename = "bigfile.txt";
const char *out_filename = "out_file.bin";

int main()
{

    int ch = 0;

    /* ASCII */
    FILE *in_file = NULL;

    in_file = fopen(in_filename, "r");

    if(!in_file)
    {
         fprintf(stderr, "ERROR: Could not open file %s ... ", in_filename);
         exit(EXIT_FAILURE);
    }

    /* Binary */
    FILE *out_file = NULL;

    out_file = fopen(out_filename, "w+b");

    if(!out_file)
    {
         fprintf(stderr, "ERROR: New file %s, could not be created ... ", out_filename);
         exit(EXIT_FAILURE);

    }

    while(1)
    {
        ch = fgetc(in_file);
            if(ch == EOF)
                break;
            else
               fwrite(in_file, sizeof(char), 1, out_file);
    }

        fclose(in_file);
        fclose(out_file);

    return 0;

}

我正在使用这个 shell 脚本生成输入文件:

tr -dc "0-9" < /dev/urandom | fold -w100|head -n 100000 > bigfile.txt

任何帮助将不胜感激。

谢谢。

【问题讨论】:

  • 也许我误解了你的作业,但是当我阅读它时,你想将你的 ASCII 测试文件读取为 数字,也许使用fscanf(in_file, "%d", &amp;ch)。如果你这样做,一个包含“18 52 86 120”的输入文件将产生一个包含四个字节0x120x340x560x78的4字节二进制输出文件。跨度>
  • 如果你能让它以这种方式工作,如果你给它输入72 101 108 108 111 44 32 119 111 114 108 100 33 10,你应该最终得到一个“二进制”输出文件,毕竟它实际上也是一个文本文件。 ..
  • 您在这里的问题“我应该在输出中看到什么,它应该与输入相同/不同吗?”是我想问你的第一件事,也是我要问我的导师的第一件事。这不是一门英语课程,其目的是了解问题所在——它是一门编程课程。正如所写,这个问题感觉很糟糕。我希望至少有一个输入和输出样本......
  • @enhzflep 感谢您的建议,我刚改了标题,抱歉写得不好,英语不是我的第一语言。
  • @SteveSummit 感谢您的评论,我想向您请教一个很好的资源来更好地理解这些主题,因为我目前阅读的这本书我认为在某些方面非常有限......

标签: c ascii binaryfiles


【解决方案1】:
fwrite(in_file, sizeof(char), 1, out_file);

是错误的,因为在需要指针的地方给出了一个整数。

你可以用fputc写一个字节像

fputc(in_file, out_file);

如果你出于某种原因还想使用fwrite,准备一个数据来写,像这样写

{
    unsigned char in_file_byte = in_file;
    fwrite(&in_file_byte, sizeof(in_file_byte), 1, out_file);
}

现在输出文件的内容将与输入文件相同。某些系统可能会执行换行符的转换,由于输入文件是以文本模式打开的,因此可能会导致内容不同。

【讨论】:

  • 感谢您的反馈,我已经尝试用fgetc() 替换fwrite(),但这让我更加怀疑,因为现在我有相同的输入和输出,即使输出应该不同,因为 ASCII 文件和二进制文件应该看起来不一样吧?
  • @PaulS-Pou 如果不执行转换,它们应该看起来相同。只是如何解释数据(字节)的问题。
【解决方案2】:

以文本模式或二进制模式打开文件与 ASCII/二进制转换无关。 它与操作系统如何处理某些特殊字符(例如换行符)、行大小限制或文件扩展名有关。

fopen Linux 手册页中:

模式字符串还可以包含字母“b”作为最后一个字符或作为任何两个字符字符串 de- 中的字符之间的字符。 上面写的。这完全是为了与 C8​​9 兼容,没有任何效果; 'b' 在所有符合 POSIX 的系统上都被忽略,包括 Linux。 (其他 系统可能会以不同的方式处理文本文件和二进制文件,如果您对二进制文件执行 I/O 并期望您的程序 可以移植到非 UNIX 环境。)

有关以文本或二进制模式打开文件的更多信息,请参阅https://stackoverflow.com/a/20863975/6874310

现在,回到 ASCII 转换:

计算机中的所有数据都存储在位中,因此最终一切都是二进制的。

包含 ASCII 字符的文本文件也是二进制文件,只是它的内容可以以有意义的方式映射到 ASCII 表字符。

看看ASCII table。 ASCII 字符数字零 (0) 的二进制值为 0x30。这意味着您在文本文件中看到的零实际上是 内存中的二进制数0x30

您的程序正在从一个文件读取数据并写入另一个文件,而不执行任何 ASCII/二进制转换。

另外,这里有个小错误:

fwrite(in_file, sizeof(char), 1, out_file);

应该是这样的:

fwrite(&ch, sizeof(char), 1, out_file);

这会将变量ch 中的字节写入out_file。 通过此修复,程序基本上从文件bigfile.txt 中读取数据并将完全相同的数据写入文件out_file.bin,而无需进行任何转换。

要将单个数字 ASCII 数字转换为二进制,请从输入文件中以字节形式读取数字(char 类型)并从中减去 0x30

char ch = fgetc(in_file);

if(ch == EOF)
{
    break;
}
else if (isdigit(ch))
{
   ch = ch - 0x30;
   fwrite(&ch, sizeof(char), 1, out_file);
}

现在,您的输出文件实际上是二进制文件。 使用 isdigit 确保字节是 ASCII 数字。在文件开头添加#include &lt;ctype.h&gt; 以使用它。

因此,对于具有以下文本的小型输入文件:

123

它的二进制表示是:

0x313233

而且,ASCII 数字转换成二进制后,二进制内容为:

0x010203

要将其转换回 ASCII,只需反转转换即可。即在二进制文件的每个字节中添加0x30

如果您使用的是类 Unix 系统,您可以使用命令行工具(例如 xxd)来检查二进制文件。在 Windows 上,任何 Hex Editor 程序都可以完成这项工作。

【讨论】:

  • 感谢您的详细解释,它解决了我一开始的所有疑问,我不知道为什么我想象在fopen() 上使用 b 标志会变魔术。但这解决了我所有的疑问,非常感谢。
  • 酷!我记得当我第一次学习这个时,我很困惑。有些教程在解释这些标志时非常模糊。
猜你喜欢
  • 1970-01-01
  • 2022-01-13
  • 2017-11-29
  • 1970-01-01
  • 1970-01-01
  • 2011-05-25
  • 1970-01-01
  • 1970-01-01
  • 2019-03-19
相关资源
最近更新 更多