二进制输出应该与 ASCII 输入相同吗?

Should the binary output be the same as the ASCII input?

我正在编写一个读取 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

任何帮助将不胜感激。

谢谢。

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);
}

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

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

fopen Linux 手册页中:

The mode string can also include the letter 'b' either as a last character or as a character between the characters in any of the two-character strings de‐ scribed above. This is strictly for compatibility with C89 and has no effect; the 'b' is ignored on all POSIX conforming systems, including Linux. (Other systems may treat text files and binary files differently, and adding the 'b' may be a good idea if you do I/O to a binary file and expect that your program may be ported to non-UNIX environments.)

有关以文本或二进制模式打开文件的详细信息,请参阅

现在,回到 ASCII 转换:

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

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

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

您的程序正在从一个文件读取数据并写入另一个文件,但未执行任何 ASCII/binary 转换。

另外,这里有个小错误:

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 <ctype.h> 以使用它。

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

123

它的二进制表示将是:

0x313233

并且,将ASCII码转换为二进制后,二进制内容为:

0x010203

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

如果您使用的是类 Unix 系统,则可以使用 xxd 等命令行工具来检查二进制文件。 Windows,任何十六进制编辑器程序都可以完成这项工作。