在scala.io.Source.fromFile期间捕获MalformedInputException

时间:2018-02-05 09:42:20

标签: scala character-encoding

我使用scala.io.Source.fromFile方法读取csv文件。有时,文件将以不同的编码格式进行编码。我允许用户指定文件enconding但是...如果用户没有指定正确的编码我想捕获MalformedInputException然后我的方法将返回None(而不是一些[迭代[字符串]])。

我使用Codec的onCodingException方法,但似乎没有得到应用。请参阅下面的代码:

def readFileAsIterator(fileName: String,
                     encoding: Option[String] = Some(defaultEncoding)): Option[Iterator[String]] = {
try {
  val codecType = encoding.getOrElse(defaultEncoding)
  implicit val codec = Codec(codecType)
  codec.onCodingException {
    case e: CharacterCodingException =>  {
      throw (new MalformedInputException(2))
    }
  }
  val fileLines = io.Source.fromFile(fileName)(codec).getLines()
  Some(fileLines)
} catch {
  case e: Exception => {
    None
  }
}
}

有人玩过这种方法并设法让它发挥作用吗?

3 个答案:

答案 0 :(得分:0)

你应该考虑在这里修改两件事,

1 - 返回Try[Iterator[String]]而不是Option[Iterator[String]]

2 - encoding可以是具有默认值的String

def readFileAsIterator(fileName: String, encoding: String = "UTF-8"): Try[Iterator[String]] = Try({
  implicit val codec = Codec(encoding)
  codec.onCodingException({
    case e: CharacterCodingException => 
      throw (new MalformedInputException(2))
  })
  io.Source.fromFile(fileName)(codec).getLines()
})

答案 1 :(得分:0)

io.Source.fromFile(fileName)(codec).getLines()

返回懒惰的Iterator [String]。因此异常发生在迭代上,而不是立即在迭代器创建上发生。 想想,一般情况下,如果没有解析之前就不可能检测到错误的编码,所以你需要首先解析文件以了解编码是否正确而不是返回新创建的迭代器(不是用于解析!),或者将异常处理留给调用者代码,用于解析数据。 或者是一种权衡,例如读取几个第一行,如果可以(没有编码异常)为调用者创建新的迭代器,但要理解在某些情况下调用者将在以后错误的编码行上获得异常。

<强>更新

根据其他答案回复您对我的评论。

检查一下:

def readFileAsIterator(fileName: String,
                     encoding: Option[String] = Some("IBM1098"),
                     touchIterator: Boolean = false): Option[Iterator[String]] = {
try {
  val codecType = encoding.getOrElse("IBM1098")
  implicit val codec = Codec(codecType)
  codec.onCodingException {
    case e: CharacterCodingException =>  {
      throw new MalformedInputException(2)
    }
    case e: java.nio.charset.UnmappableCharacterException =>  {
      throw new MalformedInputException(3)
    }
  }
  if (!touchIterator) {
    Some(scala.io.Source.fromFile(fileName)(codec).getLines())
  } else {
    val i = scala.io.Source.fromFile(fileName)(codec).getLines()
    if (i.hasNext) {
      Some(i)
    } else {
      None
    }
  }
} catch {
  case e: Exception => {
    log.info(s"Handled exception in func", e)
    None
  }
}
}

对文件的两次调用导致异常(在我的情况下是UnmappableCharacterException),触摸迭代器而不依赖于其他参数。

在幕后你就像我说的那样有迭代器。它是惰性缓冲迭代器。所以它在第一次调用时初始化(在修改后的方法中我强制用hasNext初始化它)。 我不认为它读取整个文件,只是缓冲它的一部分(因此它是我的&#34的自动实现;权衡案例&#34;)。

答案 2 :(得分:0)

有相同的错误。我使用onMalformedInput()处理了它,如下所示:

implicit val codec = Codec("UTF-8")       
codec.onMalformedInput(CodingErrorAction.REPLACE)  
codec.onUnmappableCharacter(CodingErrorAction.REPLACE)
for(line <- Source.fromFile("..").getLines()) {
  ...
}