Javaでバイナリ/テキストファイルタイプを判別しますか?
質問
つまり、アーカイブ(jar / rar / etc。)ファイルをテキスト(xml / txt、エンコーディングに依存しない)ファイルからどのように見分けますか?
解決
保証された方法はありませんが、いくつかの可能性があります:
1)ファイルのヘッダーを探します。残念ながら、ヘッダーはファイル固有であるため、RARファイルであることがわかる場合がありますが、テキストまたはバイナリのどちらかという一般的な答えは得られません。
2)文字タイプと非文字タイプの数をカウントします。テキストファイルはほとんどアルファベット文字ですが、バイナリファイル、特にrar、zipなどの圧縮ファイルでは、バイトがより均等に表現される傾向があります。
3)定期的に繰り返される改行パターンを探します。
他のヒント
file -bi {filename}
を実行します。返されるものが 'text /'で始まる場合、それは非バイナリです。それ以外の場合はそうです。 ;-)
これを作りました。 少しシンプルですが、ラテン語ベースの言語の場合は、比率を調整して問題なく動作するはずです。
/**
* 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;
}
JMimeMagic ライブラリをご覧ください。
jMimeMagicは、Javaライブラリです。 ファイルのMIMEタイプを決定する、または ストリーム。
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;
}
}
このコードを使用しましたが、英語とドイツ語のテキストでうまく機能します:
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テキストです。
ファイルに他のASCII制御文字(上記の3つを除く0x00から0x1F)が含まれている場合、おそらくバイナリデータです。
UTF-8テキストは、高位ビットを持つすべてのバイトに対して非常に特殊なパターンに従いますが、ISO-8859-1などの固定長エンコーディングは従いません。 UTF-16は頻繁にヌルバイト(0x00)を含むことができますが、1つおきの位置にのみあります。
他のものには、より弱いヒューリスティックが必要です。
お知らせするために、私はまったく異なる方法を選択しました。私の場合、ファイルは2種類しかないため、特定のファイルがバイナリファイルになる可能性は高くなります。だから
- ファイルがバイナリであると想定し、行われるべきことを実行してみてください(例:デシリアライズ)
- キャッチ例外
- テキストとしてファイルを扱う
- それが失敗した場合、ファイル自体に何か問題があります
DROID ツールを試すことができます。