为什么二进制文件不是文本文件,而所有文本文件都是二进制文件?

时间:2018-08-08 20:13:46

标签: c

将文件分为二进制或文本文件的决定因素是什么?

例如: 考虑下面的C程序

  1. binary 模式创建文件
  2. 将两个整数写入文件“ binary.txt”。

注意:在运行程序之前,请确保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”的任何人都认为其文本文件。

普通用户应该怎么称呼此文件-二进制文本文件?

7 个答案:

答案 0 :(得分:4)

@JohnBollinger在评论中总结得最好。

  

文本与二进制文件不是现代操作系统上的基本文件特征,而是文件解释的区别。

比方说,一个文件包含四个字节,这些字节具有以下十六进制值:

0x41 0x42 0x43 0x44

如果在使用ASCII编码的系统中将这些字节解释为字符,则会得到字符ABCD

如果将这些字节视为4字节整数,则在大字节序系统中将获得值0x41424344(十进制为1094861636),在小字节序系统中将获得值为0x44434241(十进制为1145258561)系统。

就计算机而言,全都是二进制文件。至于它们的含义,全都是解释。

答案 1 :(得分:3)

在现代操作系统上,文本文件和二进制文件在文件系统级别没有区别。在旧系统上,C库实现了一系列技巧,可在OS特定表示(例如0x0D 0x0A)和单字节表示'\n'之间转换换行符,供C程序读取文本模式中保存文件。处理实际的二进制内容时,不得使用此兼容性层,为此,必须在b中使用fopen()选项。

较早的操作系统曾经对文本和二进制文件使用不同的表示形式,但如今大多数已过时。

相反,许多文件系统会跟踪带有某些特定信息的可执行文件,例如Unix FS上的模式位。这些可执行文件可以是二进制文件,包含一种形式或另一种可执行代码,而其他文件是包含脚本的文本文件。

在您的示例中,文件应被视为 binary 还是 text 是有目的的。如果要将要使用的文件的 creator 读取为二进制文件,则将其命名为binary.txt会造成混淆,因为文件名扩展名.txt通常用于表示通用文本文件。 sample.bin会更加明显。

对于程序员和临时用户来说,如何解释文件的内容很重要:在旧系统上,除非文本使用的是最终保存内容的工具,否则以文本形式加载和保存文件可能会改变其内容。

例如 qemacs ,受emacs启发的程序员编辑器在加载文件时做出了巨大的努力,以确定显示和编辑内容的最佳模式:

  • 二进制vs:文本模式(默认为十六进制显示二进制)
  • 线路终止约定
  • 字符编码
  • 编程语言或其他特定于内容的显示选项...

如果不做任何修改就写回文件,则内容将被保留,因此恰好具有文本内容的二进制文件将不会被修改。否则,以上测试将确定编码新内容的正确约定。

答案 2 :(得分:3)

自提出以来,这个问题已发生重大变化。特别是,讨论中已删除了“可执行”一词。

当前问题:

  

只有创建者知道它是以二进制模式创建的,因此应将其称为二进制文件。

创建者不仅创建了文件,还提供了文件。如果没有传达目的和格式,那那将是失败的地方。

  

任何打开“ binary.txt”文件的人都认为这是文本文件。

人们可能会认为这样,但是他们仍然无法在不知道字符编码的情况下将其作为文本文件正确处理。再次,通讯失败。可能今天使用的猜测字符编码明天可能不适用于文件的内容。


原始问题的答案:

是的,这全都是解释问题。解释需要上下文和元数据。

除了别人说的话,

  • 文件不能是文本,除非您知道用于写入文件的字符编码(必须用于读取文件)。普通文件系统不存储此知识。处理文本文件的人员必须将此基本元数据传递给程序和其他人。

  • 文件不能可执行,除非您知道要使用哪个解释器程序或程序加载器加载。系统具有以下方案:

    • 类Unix:在文件系统中的文件上设置eXecutable标志。然后,如果它是“脚本”并且需要解释程序,则该脚本可以有一个shebang #!行,指示要在其中运行的程序。
    • Windows:使用PATHEXT环境变量中列出的特定文件扩展名。示例:PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC该扩展名将使用指示如何“打开”或启动它的Open动词注册。
    • 最后,该程序可以具有“文件签名”,以指示运行该程序的程序加载器。
  • 一个文件可以称为 binary (二进制),无论您是否有元数据可以将其称为文本或可执行文件,或两者都称为。

答案 3 :(得分:1)

我认为必须区分“文本”,“二进制”和“可执行文件”:

“文本”通常是指仅包含人类可读字符(字母+数字+制表符和cr / lf)的文件,即可以用文本编辑器打开而看不到奇怪内容的文件。

“二进制”的含义通常取决于上下文。例如,如果上下文是文件处理中使用的打开模式,则“二进制”表示按原样读取每个字节,而“文本”表示特定于平台的转换,例如将"\r\n"自动转换为单个"\n"适用(例如,参考FILE *fp=fopen("c:\\test.txt", "rb")FILE *fp=fopen("c:\\test.txt", "rt"))。如果上下文是程序的分发格式,则“二进制”通常表示“针对特定平台进行预编译”。这与源代码分发相反,后者的文件通常是“文本文件”。

“可执行”的含义是操作系统将文件内容解释为可执行程序。这通常意味着包含机器代码指令的文件,该机器代码指令也包含不可读的字符,因此它们通常不是“文本文件”,并且通常不解释为文本。从广义上讲,shell脚本也是“可执行文件”,因为它们包含由相应shell解释的指令。这些说明以文本形式编写,可以在文本编辑器中打开。

从这些角度来看,我认为“文本”和“二进制”是相反的术语,而“可执行”则与二者正交。

答案 4 :(得分:1)

我认为您在问两个不同的问题。

文件内容

如果文件包含文本数据,即用换行符分隔的字符行,则它是 text 文件。

否则,假定它包含严格字符数据以外的某种形式的数据,例如二进制整数,浮点数,图像像素,音乐样本,结构化二进制数据等,这意味着它是 binary 文件,即 non-text 文件。

还有许多其他文本文件格式,例如.xml.html.csv以及编程语言源代码文件。这些严格是字符文本文件,但通常根据其内容的语法具有某种内部结构。

也就是说,所有文本文件本质上都是二进制文件,从某种意义上说,组成文件中文本数据的字符,换行符等仅是最低级别的字节流。

文件名

特别是文件名扩展名后缀。按照惯例,假定扩展名为.txt的文件包含文本数据,即由某种换行符序列分隔的字符数据行。

不同的文件扩展名(如.bin.exe(或其他一百个)表示某种二进制数据文件,通常以某种方式构造。按照约定,.bin表示没有特定格式的二进制数据,即只是字节流。

此外,有些文件的扩展名为.doc.pdf(或数十种其他扩展名),表示文字处理文档文件。这些文件还包含字符文本数据,但是通常以某种严格的二进制格式存储,该格式特定于创建它的文字处理软件。

答案 5 :(得分:-1)

通常,文件只是一个字节序列。

对于您可能使用的任何计算机,字节均为8位。因此,每个字节都有256个可能的值。

暂时将我们的注意力集中在老式ASCII上。这些字节中大约有95个是普通的,可打印的字符:字母,数字,标点符号。文本文件中还会出现一些其他字符:假设是制表符,回车符,换行符和换页符('\t''\r''\n'和{{1} }。

如果文件中的每个字节都是这些打印字符之一,则该文件为文本文件。

如果文件中的任何字节不是那些打印字符之一,则该文件不是文本文件。

如果该文件供人类使用,则其创建者将仅使用普通的打印字符,它将是一个文本文件。

如果文件包含任意数据,则每个字节可能具有其256个可能值中的任何一个,并且该文件将是二进制文件。这种文件中至少有一个字节很可能是普通打印字符以外的其他字符。 (即使所有的任意字节都恰好位于一组普通的可打印字符中,它们的意义也可能不大,我们仍可以将其视为二进制文件。)

无论如何,这就是为什么理论上每个文本文件都是二进制文件,而不是每个二进制文件都是文本文件的原因。

作为一个实际示例,请尝试以下程序:

'\f'

如果编译并运行该程序,则应该发现它创建了一个包含字符串#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); } 的文本文件textfile.txt。但是,如果您检查文件12345,则应该发现它仅包含两个字节,分别为十六进制值binaryfile.bin03。这些都不是普通的打印字符,因此它是一个二进制文件。

现在,尝试稍微更改程序,进行设置

8A

如果再次运行它,则short int x = 12345; 现在将包含字符串textfile.txt,如预期的那样。 12345将再次包含两个字节,这次是十六进制值binaryfile.bin30。但是,如果您尝试打印39,则可能会看到字符binaryfile.bin0,因为90x30是字符{的ASCII码。 {1}}和0x39

答案 6 :(得分:-6)

注意::我们的讨论仅限于ASCII(多字节字符集,其他编码被预留以避免不必要的混乱)


让我们了解字符串和字符数组之间的区别

8 bits字节中,如果 unsigned ,我们可以存储0 to 255,如果 signed

,则可以存储-128 to +127

作为一个整体,如果我们看到一个字节(8 bits),则可以容纳的字节值为-128 to 255(范围)。 ASCII字符(0 to 127)的范围。

给出字符数组a[10],如果任何字节a[0] to a[9]的值超出ASCII字符范围,则它不是 string ,它只是字符数组。如果所有字节都在ASCII范围(0 to 127)内,则为 string

概括来说,字符数组的范围可以是(-128 to 255)中的任何一个。

这里重要的结论是,因为ASCII范围(0 to 127)是-128 to 255的适当子集,所有字符串都可以称为字符数组。

现在让我们将以上定义应用于 binary 文件与文本文件

如果文件中的所有字节均在ASCII(0 to 127)范围内,则应将其称为文本文件。

如果其中任何一个超出此范围,即(-128 to -1或(128 to 255)中的任何一个,则它是一个 binary 文件。

总而言之,由于ASCII范围0 to 127是(-128 to 255)的适当子集,所以所有文本文件都是二进制文件

如果文件距离(-128 to -1或(128 to 255)至少有一个字节,则它不能是仅文本文件的二进制文件

如果任何ASCII范围字符具有特殊处理,我尚未验证标准。但总而言之,我认为我已经清楚了文本文件二进制文件的区别。

希望这会有所帮助