web-dev-qa-db-ja.com

Javaでバイナリ/テキストファイルタイプを決定していますか?

つまり、アーカイブ(jar/rar/etc)ファイルとテキスト(xml/txt、エンコーディングに依存しない)ファイルをどのように区別しますか?

42
yanchenko

保証された方法はありませんが、ここにいくつかの可能性があります:

1)ファイルのヘッダーを探します。残念ながら、ヘッダーはファイル固有であるため、RARファイルであることがわかるかもしれませんが、テキストかバイナリかというより一般的な答えは得られません。

2)文字タイプと非文字タイプの数を数えます。テキストファイルはほとんどがアルファベット文字ですが、バイナリファイル(特にrar、Zipなどの圧縮ファイル)は、バイトがより均等に表現される傾向があります。

3)定期的に繰り返される改行パターンを探します。

18
Aric TenEyck

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;
        }
    }
10
rince

file -bi {filename}を実行します。返されるものが 'text /'で始まる場合、それはバイナリではありません。それ以外の場合はバイナリです。 ;-)

10

これ作りました少しシンプルですが、ラテン語ベースの言語では、比率を調整することで問題なく動作するはずです。

/**
 *  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;
}
10
Ondra Žižka

JMimeMagic ライブラリをご覧ください。

jMimeMagicは、ファイルまたはストリームのMIMEタイプを判別するためのJavaライブラリです。

9
Daniel Hiller

私はこのコードを使用しましたが、英語とドイツ語のテキストでかなりうまくいきます:

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;
}

ファイルがバイト0x09(タブ)、0x0A(ラインフィード)、0x0C(フォームフィード)、0x0D(キャリッジリターン)、または0x20から0x7Eで構成されている場合、おそらくASCII text。

ファイルに他のASCII制御文字、上記の3つを除く0x00から0x1Fまでが含まれている場合、それはおそらくバイナリデータです。

UTF-8テキストは、高位ビットのバイトに対して非常に特定のパターンに従いますが、ISO-8859-1のような固定長エンコーディングはそうではありません。 UTF-16はしばしばヌルバイト(0x00)を含むことができますが、他のすべての位置にのみあります。

それ以外の場合は、より弱いヒューリスティックが必要になります。

3
Matthew

ただお知らせするために、私はまったく異なるパスを選択しました。私の場合、ファイルは2種類しかありません。特定のファイルがバイナリファイルになる可能性は高いです。そう

  1. ファイルがバイナリであると仮定し、実行されるはずのことを実行してみてください(例:逆シリアル化)
  2. 例外をキャッチ
  3. ファイルをテキストとして扱う
  4. それが失敗した場合、ファイル自体に問題があります
3
yanchenko
2
MarkusQ

[〜#〜] droid [〜#〜] ツールを試すことができます。

1
Fabian Steeg