【问题标题】:C++: How to check type of files without extensionC++:如何检查没有扩展名的文件类型
【发布时间】:2015-01-05 16:35:26
【问题描述】:

我正在使用boost::filesystem 搜索和处理目录中的文件。 但我不想处理每个文件(使用boost::filesystem::is_regular_file() 检查),我只想处理文本文件(或至少忽略二进制文件)。

即使文件没有扩展名,我有没有办法实现这一点?

我非常感谢独立于平台的解决方案。

【问题讨论】:

  • 检查每个文件的前 100 个字节左右的非文本字节。每个二进制文件都有一些。或者,只需在处理过程中将其作为检查的一部分,并在遇到二进制字节时放弃文件。
  • @RobertHarvey 是的,许多文本文件也是如此。例如。 Unicode BOM,或者只是 UTF-8 或 ISO-8859 或其他一些编码中的随机非 ASCII 字符。至少你需要一些阈值,比如 90% 的“文本”(
  • 嗯,另一种方法是识别每个可能的文件类型不是文本文件。大多数二进制文件和文档格式都有某种魔术字符串或其他签名。就个人而言,我认为将文件识别为文本或其他内容更容易。
  • @Robert Harvey:因为我不关心文件的确切类型(只要它是文本文件),我想我应该按照您的建议查看前几个字节。对于其余的(即如果需要进一步区分),我会假设文件可以通过它们的扩展名来区分。假设所需的文件必须只包含 UTF-8 字符:我怎样才能很好地猜测文件是否是文本文件?

标签: c++ linux boost


【解决方案1】:

使用libmagic

Libmagic 可在所有主要平台(和许多未成年人)上使用。

#include <boost/filesystem.hpp>
#include <boost/range.hpp>
#include <iostream>
#include <magic.h>

using namespace boost;
namespace fs = filesystem;

int main() {
    auto handle = ::magic_open(MAGIC_NONE|MAGIC_COMPRESS);
    ::magic_load(handle, NULL);

    for (fs::directory_entry const& x : make_iterator_range(fs::directory_iterator("."), {})) {
        auto type = ::magic_file(handle, x.path().native().c_str());
        std::cout << x.path() << "\t" << (type? type : "UNKOWN") << "\n";
    }

    ::magic_close(handle);
}

打印,例如

sehe@desktop:~/custom/boost/status$ /tmp/test 
"./Jamfile.v2"  ASCII text
"./explicit-failures.xsd"   XML document text
"./expected_results.xml"    XML document text
"./explicit-failures-markup.xml"    XML document text

您可以使用标志来控制分类的细节,例如MAGIC_MIME:

sehe@desktop:~/custom/boost/status$ /tmp/test 
"./Jamfile.v2"  text/plain; charset=us-ascii
"./explicit-failures.xsd"   application/xml; charset=us-ascii
"./expected_results.xml"    application/xml; charset=us-ascii
"./explicit-failures-markup.xml"    application/xml; charset=utf-8

或者只加载/etc/magic:

sehe@desktop:~/custom/boost/status$ /tmp/test 
"./Jamfile.v2"  ASCII text
"./explicit-failures.xsd"   ASCII text
"./expected_results.xml"    ASCII text, with very long lines
"./explicit-failures-markup.xml"    UTF-8 Unicode text

【讨论】:

  • 看起来很有希望。我试试看
  • 我认为这正是我想要的 :-) 谢谢!我修改了它,我将MAGIC_NO_CHECK_ASCII 标志添加到magic_open() 并检查变量type 是否等于“数据”。
  • 我必须补充一点,这种方法在性能方面非常昂贵。我跑了callgrind,发现我60% 的程序成本是由magic_file 造成的。由于我必须比较很多文件,我将尝试“猜测”方法,只解析每个文件的几行,看看它是否运行得更快(但是,我不希望它更快;-))跨度>
  • 另外我必须补充一点,检查type=="data" 适用于我测试过的大多数(几乎所有)文件。然而,有些文件被识别为 data 类型,但实际上是二进制文件。
  • "data" 表示二进制。当然,当“二进制”文件只包含 0x00 0x20 对时,它将被识别为文本...(实际上,它文本,即使它可以解释为二进制)跨度>
【解决方案2】:

没有完美的解决方案。

您可以进行有根据的猜测,检查文件的内容。文本文件通常只包含可打印的 ASCII 文本,这会给您一些提示,但它们可能包含误导性的 UTF8 序列,例如,如果文本是用象形文字编写的。许多文件格式的标题中都包含魔法词,但是对于魔法词的位置没有统一的约定,因此您可以轻松构建一个包含 5 种不同格式的魔法词的文件,所有这些都在正确的位置。

有时真的很难确定你看到的是什么类型的文件:

cat =13 /*/ >/dev/null 2>&1; echo "Hello, world!"; exit
*
*  This program works under cc, f77, and /bin/sh.
*
*/; main() {
      write(
cat-~-cat
     /*,'(
*/
     ,"Hello, world!"
     ,
cat); putchar(~-~-~-cat); } /*
     ,)')
      end
*/

that 是 sh-script、C 源代码还是 f77 源代码?

我建议你深入查看命令file 的源代码,它会尽最大努力去做你想做的事情。

【讨论】:

  • 回答您的问题“是 sh 脚本、C 源代码还是 f77 源代码?”...绝对是 文本。
  • 罗伯特,你在两个 cmets 中都完全正确,尤其是命令文件很难分类,因为每个人都可以编写自己的语言在命令文件中使用。
  • 我认为在您突出显示“文件”之前,罗伯特·哈维对“命令文件”的表达感到困惑 ;-) 我明白了你的意思。由于我将处理的大多数文件都是源代码文件,因此我可以假设我感兴趣的文件仅包含 UTF-8 字符。文件的具体类型并不重要。更重要的是我的程序没有开始处理二进制文件。
  • @HansKlünder 我建议你先看看我的回答 :) libmagic 一直是一个独立的东西(就像不建议查看 bash 的源代码来编辑输入行一样;你会看libreadline)
  • 顺便说一下,这是我的小测试程序对您人为输入的说明:paste.ubuntu.com/9678058
【解决方案3】:

您可以从less 窃取。 less 在当前语言环境中,如果前 256 个字节中有超过 5 个字符是 !isprint(c) &amp;&amp; !iscntrl(c),则将文件视为二进制文件。

这也是一种启发式方法(这就是为什么less 总是说“这可能是一个二进制文件”),但它是一种通常有效的常见方法,您可以调整如果您在处理某些文件时遇到问题,请设置阈值。

【讨论】:

    【解决方案4】:

    使用 libmagic 可以找到文件的类型。 man libmagic will 提供详细信息。

    浏览示例

     ` magic_t myt = magic_open(MAGIC_NONE);
      sprintf(fullfilename, "%s/%s", dir_name,filename);
      magic_load(myt,NULL);
      printf("file type is  %s", magic_file(myt,fullfilename));
      magic_close(myt);
     `
    

    【讨论】:

      猜你喜欢
      • 2012-04-02
      • 2012-06-11
      • 2018-05-05
      • 2012-06-11
      • 1970-01-01
      • 2011-08-19
      • 1970-01-01
      • 2015-09-05
      • 2015-10-03
      相关资源
      最近更新 更多