[英]Why Binary file is not a Text file and all Text files are Binary files?
将文件分类为二进制或文本文件的决定因素是什么?
例如:考虑下面的C程序
注意:在运行程序之前,请确保binary.txt不存在。
观察:
使用内容TEXTFILE创建的文件“ binary.txt”
#include <stdio.h>
int main()
{
int arr[2] = {1415071060,1162627398};
FILE *fp = fopen("binary.txt", "wb");
if(fp == NULL)
{
printf("Error opening file\n");
exit(1);
}
fwrite(arr, sizeof(arr), 1, fp);
fclose(fp);
return 0;
}
但是,只有创建者知道它是在二进制模式下创建的,因此应将其称为二进制文件。
任何打开文件“ binary.txt”的人都认为其文本文件。
一般用户应称该文件为二进制文件还是文本文件?
@JohnBollinger在评论中总结得最好。
文本与二进制文件不是现代操作系统上的基本文件特征,而是文件解释方式之间的区别。
假设一个文件包含四个字节,并具有以下字节的十六进制值:
0x41 0x42 0x43 0x44
如果在使用ASCII编码的系统中将这些字节解释为字符,则将获得字符ABCD
。
如果你把这些字节为4字节的整数,你将得到的值0x41424344
在大端系统(1094861636十进制) 0x44434241
在小端系统(1145258561十进制)。
就计算机而言,它全都是二进制文件。 至于它们的含义,全都是解释问题。
在现代操作系统上,文本文件和二进制文件在文件系统级别没有区别。 在旧系统上,C库实现了一系列技巧,可以在OS特定表示形式(例如0x0D
0x0A
)和单字节表示形式\\n'
之间转换换行符,以便C程序以文本模式读取文件。 处理实际的二进制内容时,不得使用此兼容性层,为此,必须在fopen()
使用b
选项。
较早的操作系统曾经对文本和二进制文件使用不同的表示形式,但如今大多数已过时。
相反,许多文件系统通过一些特定信息来跟踪可执行文件,例如Unix FS上的模式位。 这些可执行文件可以是二进制文件,包含一种形式或另一种可执行代码,而其他文件是包含脚本的文本文件。
在您的示例中,应将文件视为二进制文件还是文本文件是有目的的。 如果要使用的文件的创建者将被读取为二进制文件,则将其命名为binary.txt
令人困惑,因为文件扩展名.txt
通常用于表示通用文本文件。 sample.bin
会更加明显。
对于程序员和临时用户来说,如何解释文件的内容很重要:在旧系统上,以文本形式加载和保存文件可能会更改其内容,除非您使用的工具最终与保存内容有关。
例如,受emacs启发的程序员编辑器qemacs ,在加载文件时进行了大量工作,以确定显示和编辑内容的最佳方式:
如果写回该文件而没有修改,则内容将被保留,因此恰好具有文本内容的二进制文件将不会被修改。 否则,以上测试将确定用于编码新内容的正确约定。
自从提出这个问题以来,这个问题已经发生了很大变化。 特别地,术语“可执行”已从讨论中删除。
当前问题:
只有创建者知道它是在二进制模式下创建的,因此应将其称为二进制文件。
创建者不仅创建了文件,还提供了文件。 如果没有传达目的和格式,那将是失败的地方。
任何打开文件“ binary.txt”的人都认为它是文本文件。
人们可能会这样想 ,但是他们仍然无法在不知道字符编码的情况下将其作为文本文件正确处理。 再次,通讯失败。 今天使用的猜测字符编码明天可能不适用于文件的内容。
原始问题的答案:
是的,这全都是解释问题。 解释需要上下文和元数据。
除了别人说的话,
除非您知道用于写入的字符编码(并且必须用于读取它),否则文件不能是文本 。 普通文件系统不存储此知识。 处理文本文件的人员必须将此基本元数据传递给程序和其他人员。
除非您知道要使用哪个解释程序或程序加载器,否则文件不可执行 。 系统有以下方案:
#!
行,说明要在其中运行的程序。 PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
扩展PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
与一个Open动词一起注册,指示如何“打开” ”或启动它。 不管您是否有元数据可将其称为文本或可执行文件,或将两者都称为文件,文件可称为二进制文件。
我认为必须区分“文本”,“二进制”和“可执行文件”:
“文本”通常是指仅包含人类可读字符(字母+数字+制表符和cr / lf)的文件,即,您可以使用文本编辑器打开的文件而看不到奇怪的东西。
“二进制”的含义通常取决于上下文。 例如,如果上下文是文件处理中使用的打开模式,则“二进制”表示按原样读取每个字节,而“文本”表示特定于平台的转换,例如将"\\r\\n"
自动转换为单个"\\n"
适用(例如, FILE *fp=fopen("c:\\\\test.txt", "rb")
与FILE *fp=fopen("c:\\\\test.txt", "rt")
)。 如果上下文是程序的分发格式,则“二进制”通常表示“针对特定平台进行预编译”。 这与源代码分发相反,后者的文件通常是“文本文件”。
“可执行”的含义是操作系统将文件内容解释为可执行程序。 这通常意味着包含机器代码指令的文件,该机器代码指令也包含不可读的字符,因此它们通常不是“文本文件”,并且通常不解释为文本。 从广义上讲,shell脚本也是“可执行文件”,因为它们包含由相应shell解释的指令。 这些说明以文本形式编写,可以在文本编辑器中打开。
从这些角度来看,我认为“文本”和“二进制”是相反的术语,而“可执行”则与二者正交。
我认为您在问两个不同的问题。
文件内容
如果文件包含文本数据,即用换行符分隔的字符行,则它是文本文件。
否则,假定它包含严格字符数据以外的某种形式的数据,例如二进制整数,浮点数,图像像素,音乐样本,结构化二进制数据等,这意味着它是一个二进制文件,即非文本文件。
还有许多其他文本文件格式,例如.xml
, .html
, .csv
以及编程语言源代码文件。 这些严格是字符文本文件,但通常基于其内容的语法具有某种内部结构。
就是说,所有文本文件在本质上都是二进制文件,从某种意义上说,文件中包含文本数据的字符,换行符等仅是最低级别的字节流。
文档名称
具体来说,是文件扩展名或后缀 。 按照惯例,假定扩展名为.txt
文件包含文本数据,即由某种换行符序列分隔的字符数据行。
诸如.bin
或.exe
(或其他一百个)之类的不同文件扩展名表示某种二进制数据文件,通常以某种方式构造。 按照约定, .bin
表示没有特定格式的二进制数据,即仅字节流。
此外,有些文件的扩展名如.doc
或.pdf
(或数十种其他扩展名),表示文字处理文档文件。 这些文件也包含字符文本数据,但是通常以某种严格的二进制格式存储,该格式特定于创建它的文字处理软件。
通常,文件只是一个字节序列。
对于您可能使用的任何计算机,字节均为8位。 因此,每个字节都有256个可能的值。
目前,我们的注意力仅限于老式ASCII。 这些字节中大约有95个是普通的,可打印的字符:字母,数字,标点符号。 文本文件中还会出现一些其他字符:假设是tab,回车,换行和换页( '\\t'
, '\\r'
, '\\n'
和'\\f'
)。
如果文件中的每个字节都是这些打印字符之一,则该文件为文本文件。
如果文件中的任何字节不是这些打印字符之一,则该文件不是文本文件。
如果该文件供人类使用,则其创建者将仅使用普通的打印字符,并且它将是一个文本文件。
如果文件包含任意数据,则每个字节可能具有其256个可能的值中的任何一个,并且该文件将是一个二进制文件。 这种文件中至少有一个字节很可能是普通打印字符以外的其他字符。 (即使所有的任意字节都恰好位于普通的可打印字符集中,它们也可能意义不大,我们可能仍将其视为二进制文件。)
无论如何,这就是为什么每个文本文件理论上都是二进制文件,而不是每个二进制文件都不是文本文件的原因。
作为一个实际示例,请尝试以下程序:
#include <stdio.h>
int main()
{
short int x = 906;
FILE *fp1 = fopen("textfile.txt", "w");
FILE *fp2 = fopen("binaryfile.bin", "wb");
if(fp1 == NULL || fp2 == NULL) exit(1);
fprintf(fp1, "%d\n", x);
fwrite(&x, sizeof(x), 1, fp2);
fclose(fp1);
fclose(fp2);
}
如果编译并运行该程序,则应发现它创建了一个包含字符串12345
的文本文件textfile.txt
。 但是,如果您检查文件binaryfile.bin
,则应该发现它仅包含两个字节,十六进制值为03
和8A
。 这些都不是普通的打印字符,因此它是一个二进制文件。
现在,尝试稍微更改程序,设置
short int x = 12345;
如果再次运行它,则textfile.txt
现在将包含字符串12345
,与预期的一样。 binaryfile.bin
将再次包含两个字节,这次的十六进制值为30
和39
。 但是,如果尝试打印binaryfile.bin
,则可能会看到字符0
和9
,因为0x30
和0x39
是字符0
和9
的ASCII码。
注意:我们的讨论仅限于ASCII(多字节字符集,其他编码被预留以避免不必要的混淆)
让我们了解字符串和字符数组之间的区别
在一个字节8 bits
,我们可以存储0 to 255
如果无符号 , -128 to +127
一旦签署
总体来说,如果我们看到一个字节( 8 bits
),则可以容纳的值是-128 to 255
(范围)。 ASCII字符的范围( 0 to 127
)。
给定字符数组a[10]
如果字节a[0] to a[9]
任何a[0] to a[9]
值超出ASCII字符范围的范围,则它不是字符串 ,而是字符数组。 如果所有字节都在ASCII范围内( 0 to 127
),则为字符串 。
总之,对于字符数组,范围可以是-128 to 255
任何一个。
这里的重要结论是,因为ASCII范围( 0 to 127
)是-128 to 255
的适当子集,所以所有字符串都可以称为字符数组。
现在让我们将以上定义应用于二进制 文件还是文本文件 。
如果文件中的所有字节均在ASCII范围内( 0 to 127
),则应将其称为文本文件。
如果它们中的任何一个超出此范围,即(-128 to -1
)或( 128 to 255
)中的任何一个,则它是一个二进制文件。
总之,由于ASCII范围0 to 127
是( -128 to 255
)的适当子集,所以所有文本文件都是二进制文件 。
如果文件的( -128 to -1
)或( 128 to 255
)至少有一个字节, 它不能是文本文件的二进制文件 。
如果任何ASCII范围字符具有特殊处理,我尚未验证标准。 但总而言之,我想我清楚了文本文件与二进制文件之间的区别。
希望这可以帮助
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.