在Java中确定二进制/文本文件类型?

时间:2009-03-07 00:31:04

标签: java file text binary

即,您如何从文本(xml / txt,独立于编码)中记录归档(jar / rar / etc。)文件?

11 个答案:

答案 0 :(得分:17)

没有保证的方法,但这里有几种可能性:

1)在文件上查找标题。遗憾的是,标题是特定于文件的,因此虽然您可能会发现它是一个RAR文件,但您无法获得更为通用的答案,无论是文本还是二进制文件。

2)计算字符与非字符类型的数量。文本文件主要是字母字符,而二进制文件 - 尤其是rar,zip等压缩文件 - 往往会更均匀地表示字节。

3)寻找定期重复的换行模式。

答案 1 :(得分:10)

运行file -bi {filename}。如果它返回的是以'text /'开头的,则它是非二进制的,否则就是。 ; - )

答案 2 :(得分:9)

查看JMimeMagic库。

  

jMimeMagic是一个Java库   确定文件的MIME类型或   流。

答案 3 :(得分:9)

我做了这个。 有点简单,但对于基于拉丁语言,它应该可以正常工作,并进行比率调整。

/**
 *  Guess whether given file is binary. Just checks for anything under 0x09.
 */
public static boolean isBinaryFile(File f) throws FileNotFoundException, IOException {
    FileInputStream in = new FileInputStream(f);
    int size = in.available();
    if(size > 1024) size = 1024;
    byte[] data = new byte[size];
    in.read(data);
    in.close();

    int ascii = 0;
    int other = 0;

    for(int i = 0; i < data.length; i++) {
        byte b = data[i];
        if( b < 0x09 ) return true;

        if( b == 0x09 || b == 0x0A || b == 0x0C || b == 0x0D ) ascii++;
        else if( b >= 0x20  &&  b <= 0x7E ) ascii++;
        else other++;
    }

    if( other == 0 ) return false;

    return 100 * other / (ascii + other) > 95;
}

答案 4 :(得分:7)

使用Java 7 Files类http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#probeContentType(java.nio.file.Path)

boolean isBinaryFile(File f) throws IOException {
        String type = Files.probeContentType(f.toPath());
        if (type == null) {
            //type couldn't be determined, assume binary
            return true;
        } else if (type.startsWith("text")) {
            return false;
        } else {
            //type isn't text
            return true;
        }
    }

答案 5 :(得分:5)

我使用了这段代码,它适用于英语和德语文本:

private boolean isTextFile(String filePath) throws Exception {
    File f = new File(filePath);
    if(!f.exists())
        return false;
    FileInputStream in = new FileInputStream(f);
    int size = in.available();
    if(size > 1000)
        size = 1000;
    byte[] data = new byte[size];
    in.read(data);
    in.close();
    String s = new String(data, "ISO-8859-1");
    String s2 = s.replaceAll(
            "[a-zA-Z0-9ßöäü\\.\\*!\"§\\$\\%&/()=\\?@~'#:,;\\"+
            "+><\\|\\[\\]\\{\\}\\^°²³\\\\ \\n\\r\\t_\\-`´âêîô"+
            "ÂÊÔÎáéíóàèìòÁÉÍÓÀÈÌÒ©‰¢£¥€±¿»«¼½¾™ª]", "");
    // will delete all text signs

    double d = (double)(s.length() - s2.length()) / (double)(s.length());
    // percentage of text signs in the text
    return d > 0.95;
}

答案 6 :(得分:3)

如果文件由字节0x09(制表符),0x0A(换行符),0x0C(换页),0x0D(回车符)或0x20到0x7E组成,那么它可能是ASCII文本。

如果文件包含除上述三个之外的任何其他ASCII控制字符,0x00到0x1F,那么它可能是二进制数据。

对于具有高阶位的任何字节,UTF-8文本遵循非常特定的模式,但是像ISO-8859-1这样的固定长度编码则不然。 UTF-16通常可以包含空字节(0x00),但只能包含其他所有位置。

你需要一个较弱的启发式方法。

答案 7 :(得分:3)

只是为了让你知道,我选择了一条完全不同的道路。我的情况是,只有两种类型的文件,任何给定文件都是二进制文件的机会很高。所以

  1. 假设文件是​​二进制文件,尝试执行应该执行的操作(例如反序列化)
  2. 捕捉异常
  3. 将文件视为文字
  4. 如果失败,文件本身有问题

答案 8 :(得分:2)

答案 9 :(得分:2)

你可以试试 Apache Tika,我已经打开了一个 request specifically for this feature

但就目前而言,我认为这可能有效......需要更彻底的测试,也可能存在其他 mime 类型库的问题,其中您仍然确实需要从类型到它是否为二进制的映射。

var config = TikaConfig.getDefaultConfig();
var tika = new Tika( config );
var mimeTypes = config.getMimeRepository();

var mimetype = tika.detect(Path.of("my/foo"));
var rootType = mimeTypes.forName( mime ).getType().getType();
rootType.endsWith( "text" ); // text and x-text

答案 10 :(得分:1)

您可以尝试DROID工具。