如何检查一个文件是否为纯文本?

8
在我的程序中,用户可以加载包含链接的文件(这是一个网络爬虫),但我需要验证用户选择的文件是纯文本还是其他格式(只允许纯文本)。
是否有可能实现这个功能?如果有用的话,我正在使用JFileChooser来打开文件。
编辑:
用户应提供包含URL的文本文件。
我要避免的是用户加载MP3文件或MS Word文档等其他格式的文件。
6个回答

5

一个文件只是一系列字节,如果没有更多的信息,你无法确定这些字节是否应该是某个字符串编码中的代码点(比如ASCII或UTF-8或ANSI-something)或者其他内容。你需要采用一些启发式方法,例如:

  • 尝试在多种已知的编码中解析文件,并查看解析是否成功。如果成功了,那么很可能你有一个文本文件。
  • 如果你只期望西方语言的文本文件,你可以假设大部分字符都在ASCII范围内(0..127),更具体地说,是(33..127)以及空白符(制表符、换行符、回车符、空格)。统计每个不同字节值的出现次数,如果你的文档中绝大部分都是“典型的西方字符”集合中的字符,通常可以安全地假设它是一个文本文件。
  • 扩展上述方法;在你预期的语言中随机抽样足够数量的文本,并构建字符频率文件。要检查你的文件,请将文件的字符频率文件与你的测试数据进行比较,看看它们是否足够接近。

但这里还有另一个解决方案:将你收到的所有内容视为文本,在需要时应用必要的转换(例如发送到Web浏览器时进行HTML编码)。只要防止文件被解释为二进制数据(例如用户双击文件),你最糟糕的情况就是产生一些无意义的数据。


2

文本也是一种二进制数据形式。

我想你想要检查的是输入中是否有任何字符小于32。如果你可以安全地假设你的文本是多字节编码的,那么你可以扫描整个文件,并在遇到范围为[0,32)(不包括9、10、13和其他你可能期望在“文本”中除外的内容,或者最坏情况下仅检查空字节[感谢tdammers!])的字节时中止。如果你可能会收到UTF-16或UTF-32编码的文本,则需要更加努力。


制表符、换行符和回车符均小于32。 - tdammers
@tdammers:哎呀,发现得好。好的,从匹配中排除它们!那换行符呢? :-) - Kerrek SB
我可能会检查文件是否为UTF-8编码,如果它是有效的UTF-8编码(除了制表符、换行符和回车符之外,还有可能排除32以下的代码点和127),那就假定它是文本。 - MRAB
@MRAB:你是指什么?对于有效的多字节序列的正式检查已经包含在我的答案中了,但是对于完整的Unicode有效性检查,您还必须检查编码字符是否是有效的代码点。 - Kerrek SB

1

您还可以检查初始字节是否为BOM,这应该表示一个UTF文件:

- UTF-8     => 0xEF, 0xBB, 0xBF
- UTF-16 BE => 0xFE, 0xFF
- UTF-16 LE => 0xFF, 0xFE

罗桑


1

如果您不想通过文件扩展名猜测文件类型,您可以读取文件的前一部分。但下一个问题将是字符编码。使用BufferedInputStream(在mark()之前和reset()之后),用编码为"ISO-8859-1"InputStreamReader包装,并使用Character.isLetterOrDigit()Character.isWhitespace()计算读取的字符数,以获取典型文本内容的比率。我认为对于文本文件,这个比率应该超过80%。

您也可以尝试其他编码,如UTF-8,但当它不是UTF-8时,可能会遇到无效字符的问题。


我可以轻松地将图像的扩展名更改为“.TXT”,并尝试将其加载到一个试图打开“文本”文件的应用程序中,从而导致它崩溃。 - Si8
@SiKni8:那不是问题,一个好的应用程序在打开二进制文件时不会崩溃! - Arne Burmeister

0
您应该创建一个过滤器,查看文件描述并检查文本。

0

你可以从Java中调用shell命令file -i ${filename},并检查输出以查看是否包含类似于charset=binary的内容。如果是,则它是二进制文件。否则它是基于文本的文件。

你可以在shell中尝试使用file来处理各种文件,并熟悉它。在Groovy中,我会写出类似于:

'file -i ${path/to/myfile}'.execute().getText().contains('charset=binary')

在Java中,你也可以调用shell命令。请参考this


在 macOS 上,我使用 'file --help' 命令发现应该使用 '-I' 来输出 MIME 类型,而不是 '-i',后者只会输出“常规文件”。 - K. Symbol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接