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

Posted

技术标签:

【中文标题】如何在 Java/Scala 中跳过流中的无效字符?【英文标题】:How to skip invalid characters in stream in Java/Scala? 【发布时间】:2011-11-09 00:08:03 【问题描述】:

例如我有以下代码

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)

我不在乎是否有一些行没有被读取,但是如何跳过无效字符并继续读取行?

【问题讨论】:

【参考方案1】:

您可以通过调用CharsetDecoder.onMalformedInput 来影响字符集解码处理无效输入的方式。

通常您永远不会直接看到CharsetDecoder 对象,因为它将在幕后为您创建。因此,如果您需要访问它,则需要使用允许您直接指定 CharsetDecoder 的 API(而不仅仅是编码名称或 Charset)。

此类 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")(或使用 Guava 中的 the Charsets class)。

【讨论】:

+1 向我介绍了 StandardCharset。我想要那个很久了。没有了catch (UnsupportedEncodingException e) // never happens @Thilo:如果你坚持使用 Java 6,那么 Guava 提供了 the Charsets class,它可以做同样的事情。 注意:如果您正在写入文件,您可能会遇到类似的错误。您也可以在 CharsetEncoder 上设置相同的 onMalformedInput: IGNORE。【参考方案2】:

好吧,如果不是 UTF-8,那就是别的东西。诀窍是找出其他东西是什么,但是如果您只想避免错误,则可以使用没有无效代码的编码,例如latin1

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

【讨论】:

不幸的是,有时某些来源提供“主要是 UTF-8”并包含格式错误的输入。在这些情况下,跳过损坏的字符并仍然解码正确的字符可能是可以接受的。【参考方案3】:

我遇到了类似的问题,Scala 的一个内置编解码器为我解决了问题:

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

【讨论】:

哇,我不知道为什么会这样,但你拯救了我的夜晚!【参考方案4】:

如果你想避免使用 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)
    
  

【讨论】:

以上是关于如何在 Java/Scala 中跳过流中的无效字符?的主要内容,如果未能解决你的问题,请参考以下文章

你如何在GNU Awk 4.2中跳过使用FIELDWIDTHS的字符?

使用FilterInputStream的跳过方法

Scanf 在循环中跳过(Hangman)

如何在正则表达式中匹配 \n 但从以下文本中跳过 n?

如何从mysql中的表中跳过行

如何在 Fortran 90 中跳过带有“#”符号的行? [复制]