扩展名和文件内容都只能用来”辅助“判断文件类型。或者说都是 heuristic,再直白点说就是都是不靠谱的。
我做 3D 建模会用到 Wavefront .obj 文件,这扩展名很明显和 Windows 的 Object File 冲突了,然而它是 3D 多边形模型的一种 ASCII 表示,并不能当作 Object File 来用。这个好像还算好的,但是 Wavefront .obj 是很老的东西了,现在流行用 Alembic 格式 (.abc),这个扩展名,我查到的至少有四种用途,我显出极高兴的样子,将两个指头的长指甲敲着柜台,问楼主,这四种用途,你知道么?
而且扩展名是文件名的一部分,我每次输入文件名都得写一遍,为了简短还不得不用缩写,这不仅大大增大了冲突,而且还严重影响用户友好性——不仅是更麻烦了,每个新用户都必须学习”扩展名“这种概念,稍微 non-trivial 的用户必须学习如何 disambiguate 扩展名,我犯得着么?(顶级域名的情况貌似很类似,还得附加一条被少数实体控制垄断,甚至有人喜欢用奇葩的顶级域名凑字)
根据文件内容判断就更不用说了,C 和 C++ 头文件的扩展名都是 .h (虽然我写 C++ 会用 .hxx/.cxx ,架不住大多数 C++ 项目用 .h ),我 file 一个 C++ 头文件告诉我是 C source ... 更离谱的是就连 Standard ML 源码都会给我报成 C source ... 综合看来,如果用于程序识别,还没扩展名靠谱呢
更不用说两者都有完全无法识别的 ”any“ case
有些文件管理器会把两种 heuristic 结合起来用,但是这种事情就像一个烂剧,剧本本身就烂透了,多请两个大腕明星还是烂剧。
这个问题的根源在”数据“和”解释数据的方式“一般是分离的。比如 UNIX 下的 file 命令使用 libmagic 来实现,libmagic 有一个数据库(说是一个 DSL 库也无所谓),定义了一堆 heuristic 来判断到底是什么文件(
https://github.com/file/file/tree/master/magic/Magdir )。显然这是不靠谱的,正确地判断文件类型你得给每种文件配一个 verifier,比如检查是不是 C++ 源码你得放一个 C++ 编译器进去,这就有点像停机问题了 ...
再说到底“文件“这个东西本身就是个主要考虑地球人类整体水平和智商兼容的设计,必然会遇到这种问题,本贴只是冰山一角罢了。