你想知道如何区分归档文件(jar/rar等)和文本文件(xml/txt,与编码无关)?
没有百分百准确的方法,以下是一些可能性:
查找文件头标识。不过,文件头标识是特定于文件类型的,所以你可能只能找到它是RAR文件,但不能得出更为普遍的答案,即它是文本文件还是二进制文件。
计算字符和非字符类型的数量。文本文件将主要包含字母字符,而二进制文件——尤其是像rar、zip等压缩文件——将倾向于均匀地表示字节。
查找定期重复的换行符模式。
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;
}
}
这是我做的一个版本。相对简化一些,但对于拉丁字母的语言来说,应该可以很好地工作,只需要进行比例调整。
/**
* 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;
}
return (ascii + other) * 100 / other > 95;
除非我漏掉了什么,否则它总是返回true:大多数情况下,大小将为1024
,数据长度和(ascii + other)
也将为1024
。
因此,如果(ascii + other) * 100 == 102400
,
那么102400 / other > 95
=>102400 > 95 * other
=>other < 1078
这意味着需要有超过1078(1024个之外)的“其他”才能返回false,显然是不可能的。
你的意思是吗?(other / size * 100 > 95)
还是我漏掉了什么? - Inversus运行file -bi {filename}
。如果它返回的内容以"text/"开头,那么这是非二进制文件,否则就是二进制文件。;-)
file -i {文件名}
命令检查,确保没有出现 charset=binary
。 - Steinway Wufile --help
命令发现应该使用 -bI
来输出 MIME 类型和字符集,而不是 -bi
,后者只会输出“常规文件”。 - K. Symbol请查看JMimeMagic库。
jMimeMagic是一个Java库,用于确定文件或流的MIME类型。
text/plain
,它应该是一个文本文件。 - Daniel Hillerapplication/json
也是一种文本表示形式。但是针对最初的问题非常不具体,我认为这应该足以作为一个起点 :) - 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;
}
提醒您,我选择了完全不同的方向。在我的情况下,只有两种类型的文件,任何给定文件是二进制文件的机会都很高。因此:
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