结论前置:文件名和文件内容是独立不相关联的,而文件格式与文件内容是相关的。文件名后缀仅用于提供给系统 shell 一个关于文件类型的「暗示」。更改文件后缀名不会改变文件的「格式」,只会影响「系统默认打开这个文件的方式」。
文件是什么?
文件是存储在系统存储空间(如磁盘)中的一段数据。一个文件由一个特定程序创建,包含了对这个程序有特定含义的一段字节序列,因此每次这个程序打开这同一个文件的时候,获取到的信息是一样的。其它能够与上述程序以同样方式理解这段内容的程序也可以从这个文件中获取完全一样的信息。这个「理解这段内容的方法」就是文件格式。同一段内容可以有不同的解读方法,那么我们可以认为它是同时属于几种有效格式。譬如下面一段
int main() {return 0;}
全部由可读的 ASCII 字符组成,所以它是一个纯文本文件;但熟悉 C 语言的人都可以看出这是一段 C 代码;认为它是 C++ 代码一样不会出错。
文件名是什么?
由于磁盘本身空间巨大,且有大量程序共同访问,一段内容存储在磁盘中可能不是连续的,可能位置会发生改变;且磁盘地址并非人类可以轻易理解的内容,所以有了文件名和路径。文件名和路径用于帮助人(通过程序)查找到某个特定的文件;同时文件名本身也可以作为一个「标签」告诉用户文件的内容,比如 README.txt 可以看出是一份说明文档。扩展名 txt 的部分也是类似,它只是这个文件的名字的一部分,用于告诉用户「这是一个 txt 文件」。
扩展名有什么用?
一个程序通常(或,默认)以一种特定的方式去读取用户要求它读取的文件。譬如记事簿 notepad.exe 和 vi 编辑器会默认将用户要求它打开的文件作为「纯文本格式」打开——即,文件中所有内容都是 ascii 编码、或其它系统默认编码下可以直接被人类阅读的文字。
用户打开一个文件的时候,可以是先进入某个程序再选择打开这个程序(File -> Open)或者在进入某个程序的时候同时打开某个文件(如 vi info.txt 命令);也可以通过在「文件管理器」或者其它 shell 程序中「双击」这个文件——让系统帮助「找到」合适打开这个文件的方式。Windows 系统会根据文件扩展名部分,在一个数据库中查找「可以打开这个扩展名文件的程序」,譬如 .doc 可以用 Word 打开,那么用户在双击一个 .doc 文件的时候,系统会自动启动 Word 程序,并通知 Word 去加载这个文件。OS X 一方面参考文件的扩展名,一方面会参考文件的属性(可执行权限)和文件内容(magic bits)去寻找合适的做法。
从这里可以看出,Windows 系统在打开一个文件的时候,只根据文件名中的扩展名就可以找到对应的程序。第一段中的例子
int main() { return 0; }
如果被命名为 hello.c,则系统可以调用 Visual C++ 打开;而如果命名为 hello.txt,则系统会调用记事簿打开。
这也就是为什么会有人认为,为什么改了一个文件的扩展名是更改了这个文件的类型。实际上发生了变更的只是这个文件在系统中的默认打开方式;如果文件本身内容不符合程序对文件内容格式的预期,仍然是会出错的。
同时,如果有几个扩展名都默认使用同一个程序打开,则文件扩展名与文件格式不符的情况能否正确打开取决于程序本身。如我将一个 .jpg 文件的扩展名改为 .png,而两者默认打开方式都是某图像浏览器,则系统仍然会调用这个图像浏览器打开这个文件;而这个浏览器是否对文件内容和扩展名不匹配的情况作出兼容处理还是报错,则完全取决于程序本身。
Windows 用户有一个「令人震惊」的习惯,即:右键单击桌面 -> 新建 -> 新建文本文件,然后将文件名改为 xxx.doc,双击打开。这个操作实际上只是提示 Word 去打开这个文件;而 Word 恰好对于一个刚创建的,内容完全为空(一个字符都没有)的伪・doc 文件不报错而已。这种「兼容性」实际上误导了许多人对「文件名」和「文件格式」这个基本概念的理解(转)