为什么用此代码创建的文本文件具有字符集==二进制?

时间:2019-07-07 17:46:28

标签: c linux gcc file-handling

在下面的代码中,我将创建两个文件,一个是文本格式,另一个是二进制格式。文件的图标显示相同。但是这两个文件的特性完全相同,包括大小,字符集(==二进制)和流(八位字节)。为什么没有文本文件?因为如果我明确创建文本文件,则字符集为ASCII。

  

编译器版本-gcc(Ubuntu 8.3.0-6ubuntu1)8.3.0。

     

操作系统-已在Ubuntu 18.10和19.04上试用。

     

编译器不显示消息。

     

用于检查文件file --mime的命令。

     

命令Text1.txt的输出:   Text1.txt: application/octet-stream; charset=binary

     

命令Text1.txt的输出:Binary: application/octet-stream; charset=binary

     

命令od -xa FILENAME的输出对于两个文件都是相同的,并且是:

     

0000000 0021
! 0000001

#include<stdio.h>
void main(){

FILE *fp;
FILE *fp2;
int a = 10111110;

fp2 = fopen("Text1.txt","w");
fputc('!',fp2);

fp = fopen("Binary","wb");
fputc('!',fp);

}

预期的输出是一个字符集为ASCII的文件和一个二进制文件,实际输出均为两个字符集为Binary的文件

2 个答案:

答案 0 :(得分:3)

file命令将文件诊断为二进制而不是ASCII,因为由于错误使用fputc,正在向文件写入非ASCII字符。

fputc("!",fp2);不正确。 fputc的第一个参数应该是带有字符值的int"!"是一个字符串文字,它是一个数组,会自动转换为指向其第一个字符的指针。

GCC warns you about this,说:“警告:传递'fputc'的参数1会使指针变为整数,而不进行强制转换[-Wint-conversion]”。您显然忽略了该警告。不要那样做。当编译器警告您某些事情时,请注意,诊断问题并修复。

结果是将指针转换为int,并将此int传递给fputc。这可能会导致某些非ASCII字符被写入文件,这进而导致file命令将文件诊断为二进制文件。

要解决此问题,请将字符串"!"更改为单个字符'!',以便使用fputc将单个字符传递给fputc('!',fp2);

此外,main不应用void main()声明。用int main(void)int main(int argc, char *argv[])或其他实现定义的方式声明它。

在Unix系统上,带有更正代码的结果文件将是相同的。 Core Unix不区分文本文件和二进制文件,只是某些应用程序可以使用元数据(例如“扩展属性”)以各种方式表征文件。错误代码产生的文件可能相同也可能不同,因为不同位置的相同字符串文字可能具有或不具有相同的地址,因此所得的指针可能具有或不具有相同的值。

答案 1 :(得分:0)

C在二进制流和文本流提供了原理上的区别。遍历文本流的数据可能需要进行与实现相关的转换:

  

在输入和输入时可能必须添加,更改或删除字符   输出以符合表示文本的不同约定   主机环境。因此,不必一对一   流中字符与   外部代表。从文本流读取的数据将   必须比较等于先前写入的数据   仅在以下情况下流:数据仅由打印字符组成,并且   控制字符水平制表符和换行符;没有换行   字符前面紧跟空格字符;最后一个   character是换行符。是否空格字符   在读取时出现换行符之前立即写出   in是实现定义的。

C2011, 7.21.2/2

但是,实际上,在任何可能会遇到的系统上,您将看到的针对字节流的唯一转换是在使用文本中的回车符/换行符对的系统(主要是Windows)上的行终止符转换文件。 C文本模式流将在该外部表示形式和C的仅换行符内部表示形式之间进行转换。

但是,在Linux和现代的基于BSD的macOS上,甚至没有—在实际操作中,这些操作系统在文本文件和二进制文件之间没有任何区别,并且两种生成文件的机制也就不足为奇了。文件产生相同的文件。

这是一个完全独立的问题,试图猜测文件类型的外部程序如何解释任何给定的文件,尤其是很短的文件。如果文件包含单词和句子形式的正版文本,则最好将文件检测为文本。