如何在Java/Scala中跳过流中的无效字符?

19

例如我有以下代码

Source.fromFile(new File( path), "UTF-8").getLines()

并且它会抛出异常

Exception in thread "main" java.nio.charset.MalformedInputException: Input length = 1
    at java.nio.charset.CoderResult.throwException(CoderResult.java:260)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:319)

我不在意一些行未被读取,但如何跳过无效字符并继续读取行?

4个回答

33
你可以通过调用CharsetDecoder.onMalformedInput来影响字符集解码处理无效输入的方式。
通常情况下,您不会直接看到一个CharsetDecoder对象,因为它将在幕后为您创建。因此,如果您需要访问它,您需要使用允许您直接指定CharsetDecoder(而不仅仅是编码名称或Charset)的API。
这种API的最基本示例是InputStreamReader
InputStream in = ...;
CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
decoder.onMalformedInput(CodingErrorAction.IGNORE);
Reader reader = new InputStreamReader(in, decoder);

注意,这段代码使用的是Java 7类StandardCharsets,对于早期版本,您可以简单地用Charset.forName("UTF-8")替换它(或者使用GuavaCharsets类)。

3
谢谢介绍StandardCharset给我,这是我长期以来一直想要的。再也不需要写catch (UnsupportedEncodingException e) { // never happens }了。+1。 - Thilo
5
如果你被迫使用Java 6,那么Guava提供了Charsets类(http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/base/Charsets.html),它可以完成同样的功能。 - Joachim Sauer
注意:如果您正在编写文件,则可能会出现类似的错误。您也可以在CharsetEncoder上设置相同的onMalformedInput: IGNORE。 - Richard EB

13

好的,如果不是UTF-8,那就是其他编码方式。关键在于找出这种编码方式是什么,但是如果你只是想要避免错误,你可以使用一个没有无效编码的编码方式,比如latin1

Source.fromFile(new File( path), "latin1").getLines()

有时候会遇到提供“大部分是UTF-8”的源代码,但其中包含格式不正确的输入。在这种情况下,跳过损坏的字符并仍然解码正确的字符可能是可以接受的。 - Joachim Sauer

1

我曾遇到类似问题,Scala 内置的编解码器之一对我很有帮助:

Source.fromFile(new File(path))(Codec.ISO8859).getLines()

哇,我不知道为什么这个有效,但你救了我的晚上! - habitats

0
如果你想在Scala中避免无效字符,我发现这个方法对我很有效。
import java.nio.charset.CodingErrorAction
import scala.io._

object HelloWorld {

  def main(args: Array[String]) = {
    implicit val codec = Codec("UTF-8")

    codec.onMalformedInput(CodingErrorAction.REPLACE)
    codec.onUnmappableCharacter(CodingErrorAction.REPLACE)

    val dataSource = Source.fromURL("https://www.foo.com")

    for (line <- dataSource.getLines) {

      println(line)
    }
  }
}

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