如何在 C++ 中找到底层文件类型?

Posted

技术标签:

【中文标题】如何在 C++ 中找到底层文件类型?【英文标题】:How can I find the underlying file type in C++? 【发布时间】:2014-07-15 05:23:22 【问题描述】:

在*nix 系统中有一个叫做'file'的命令,它可以告诉你一个文件的底层类型。比如说,如果您将二进制可执行文件的名称重命名为 foo.txt,或者将 mp3 文件重命名为 .txt,系统总是会告诉您文件的真实类型。但在 Windows 中,似乎没有这样的功能,如果将可执行文件重命名为 .txt,则无法执行。谁能向我解释这是如何在 *nix 系统中完成的,以及如何使用 C++ 找到文件的真实类型,尤其是在我无法使用 std::system("file blah") 的 Windows 中?

【问题讨论】:

这是一种启发式算法,它检查文件的前几个(或几百个)字节以寻找“魔术字符串”。许多类型的文件在早期就包含固定的字节序列。请参阅***上的List of file signatures。 你需要它做什么? 实际上,您可以在 Windows 中执行任何兼容的二进制文件,而不管其扩展名如何,只有 Window 的 Shell (explorer) 会阻止它。大多数商业游戏的实际可执行文件根本不是 .exe。 我写了一些应用程序来做一些自定义数据库的维护工作,有不同版本的历史数据,不同的格式和不同的扩展名。我实际上已经通过使用扩展名来确定文件的版本来完成应用程序,但这让我对文件命令感到疑惑,所以我想知道如何确定文件的真实类型。 【参考方案1】:

文件实用程序使用 libmagic 库。它识别文件类型解析文件中的“特殊”字段。 当然,您可以自己编程识别某些格式,但有时这需要大量工作。例如。当您尝试区分不同格式的 MP4 时。

该库的开发人员做了大量的工作。因此,如果你想得到上帝的结果来说明你处理的类型格式,建议使用他们的结果。(这是一个很大的领域,真的,如果知道你正在使用什么类型格式,最好依赖它们然后依赖你的代码)

文件实用程序 - http://www.darwinsys.com/file/ 你可以下载源代码,看看他们使用了多少不同的识别类型。 下载存档文件-4.26 -> magic -> Magdir

我个人很幸运能在 Windows ftp://ftp.astron.com/pub/file/ 上编译文件 4.26

警告 某些格式的文件应具有预定义的签名只是一个约定,而且几乎总是如此,有助于正确识别文件格式。 如果不是问题,您当然可以信任签名。但请记住,任何有足够知识和愿望的人都可以在十六进制编辑器中打开文件并使用位来制作另一种文件格式。

【讨论】:

【参考方案2】:

即使在 Unix/Linux 中,系统实际上也不能确切地知道文件的类型。 “文件”程序通过将文件的内容与表征各种常见文件类型的模式数据库进行比较来做出有根据的猜测,但这只是猜测——它不知道所有可能的文件格式,它可以对它确实知道的那些是错误的。

完全可以为Windows编写像“文件”这样的程序;它不依赖于操作系统中的任何特殊功能。例如,Cygwin 提供了“文件”程序的 Windows 端口。

将程序重命名为具有.txt 扩展名的问题与“文件”程序无关。这是因为 Windows 根据文件名(特别是扩展名)决定文件是否可执行,而 Unix/Linux 根据文件的权限(而不是内容)决定文件是否可执行。如果你在 Linux 系统上chmod a-x 一个程序,系统会认为它不可执行,就像你从 Windows 上的程序中删除 .exe 扩展一样。

【讨论】:

【参考方案3】:

命令reference 建议将类型信息保存到外部位置以供进一步使用。它还提到了幻数,指的是file signatures。

100% 确定文件类型在理论上是不可能的,因为对于特定类型应包含的内容没有明确的规则。即使它们是这样的规则,也可以更改文件以使其看起来像另一个文件。虽然签名和扩展都可以让您很好地了解类型实际上是什么,但您仍然需要面对处理错误类型的可能性。

【讨论】:

【参考方案4】:

UNIX file 命令使用启发式。有一个幻数数据库,通常在 /usr/share/file/magic/etc/magic/ 中,允许您添加新的文件“类型”由文件命令识别。它只是探测文件以在其内容中查找幻数(签名)。

UNIX 传统上没有与 Windows 相同类型的文件扩展名和类型关联,尽管 Linux 最近正在积累这些。

我认为在 Windows 上,您至少要检查文件扩展名关联是否正确。但即使在给定的扩展名(例如 .txt)内,单个程序也可以执行自己的启发式方法。例如,记事本在打开文件时必须对字符编码进行有根据的猜测。 Raymond Chen 在他的博客中写了一篇很好的文章The Old New Thing - The Notepad file encoding problem, redux

【讨论】:

以上是关于如何在 C++ 中找到底层文件类型?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C++ 中读取文件并将文件中的数据插入到类类型的向量中?

如何在 C++ 中找到类型的定义

在 Windows 上查找文件的 MIME 类型

C++中如何将两个连续的string 类型存入到文件中并读取出来?

如何在python中找到文件的mime类型?

如何在 C++ 中使用 mex.h