我正在尝试解析CSV文件,最好使用weka.core.converters.CSVLoader。但是,我拥有的文件不是有效的UTF-8文件。它主要是一个UTF-8文件,但一些字段值采用了不同的编码,因此没有对整个文件有效的编码,但我仍然需要对其进行解析。除了使用像Weka这样的java库之外,我主要使用Scala。我甚至不能使用scala.io.Source读取文件:例如
Source.
fromFile(filename)("UTF-8").
foreach(print);
抛出:
java.nio.charset.MalformedInputException: Input length = 1
at java.nio.charset.CoderResult.throwException(CoderResult.java:277)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:337)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:176)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:153)
at java.io.BufferedReader.read(BufferedReader.java:174)
at scala.io.BufferedSource$$anonfun$iter$1$$anonfun$apply$mcI$sp$1.apply$mcI$sp(BufferedSource.scala:38)
at scala.io.Codec.wrap(Codec.scala:64)
at scala.io.BufferedSource$$anonfun$iter$1.apply(BufferedSource.scala:38)
at scala.io.BufferedSource$$anonfun$iter$1.apply(BufferedSource.scala:38)
at scala.collection.Iterator$$anon$14.next(Iterator.scala:150)
at scala.collection.Iterator$$anon$25.hasNext(Iterator.scala:562)
at scala.collection.Iterator$$anon$19.hasNext(Iterator.scala:400)
at scala.io.Source.hasNext(Source.scala:238)
at scala.collection.Iterator$class.foreach(Iterator.scala:772)
at scala.io.Source.foreach(Source.scala:181)
我非常乐意丢弃所有无效的字符,或者用一些虚拟字符来替换它们。我将有很多这样的文本以各种方式处理,可能需要将数据传递给各种第三方库。理想的解决方案是某种全局设置,它会导致所有低级java库忽略文本中的无效字节,这样我就可以在不修改的情况下对这些数据调用第三方库。
解决方案:
import java.nio.charset.CodingErrorAction
import scala.io.Codec
implicit val codec = Codec("UTF-8")
codec.onMalformedInput(CodingErrorAction.REPLACE)
codec.onUnmappableCharacter(CodingErrorAction.REPLACE)
val src = Source.
fromFile(filename).
foreach(print)
感谢+Esailija为我指明了正确的方向。这让我想到了How to detect illegal UTF-8 byte sequences to replace them in java inputstream?,它提供了核心的java解决方案。在Scala中,我可以通过将编解码器设为隐式来使其成为默认行为。我认为我可以通过将它作为隐式编解码器定义放在package对象中,使其成为整个包的默认行为。
发布于 2012-11-29 21:04:42
这就是我如何用java做到这一点的:
FileInputStream input;
String result = null;
try {
input = new FileInputStream(new File("invalid.txt"));
CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
decoder.onMalformedInput(CodingErrorAction.IGNORE);
InputStreamReader reader = new InputStreamReader(input, decoder);
BufferedReader bufferedReader = new BufferedReader( reader );
StringBuilder sb = new StringBuilder();
String line = bufferedReader.readLine();
while( line != null ) {
sb.append( line );
line = bufferedReader.readLine();
}
bufferedReader.close();
result = sb.toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch( IOException e ) {
e.printStackTrace();
}
System.out.println(result);
无效文件是用字节创建的:
0x68, 0x80, 0x65, 0x6C, 0x6C, 0xC3, 0xB6, 0xFE, 0x20, 0x77, 0xC3, 0xB6, 0x9C, 0x72, 0x6C, 0x64, 0x94
它是UTF-8中的hellö wörld
,其中混合了4个无效字节。
使用.REPLACE
时,您会看到使用了标准的unicode替换字符:
//"h�ellö� wö�rld�"
使用.IGNORE
,您会看到被忽略的无效字节:
//"hellö wörld"
如果不指定.onMalformedInput
,您将获得
java.nio.charset.MalformedInputException: Input length = 1
at java.nio.charset.CoderResult.throwException(Unknown Source)
at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
at sun.nio.cs.StreamDecoder.read(Unknown Source)
at java.io.InputStreamReader.read(Unknown Source)
at java.io.BufferedReader.fill(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
发布于 2015-08-31 22:40:40
Scala的编解码器有一个解码器字段,它返回一个java.nio.charset.CharsetDecoder
val decoder = Codec.UTF8.decoder.onMalformedInput(CodingErrorAction.IGNORE)
Source.fromFile(filename)(decoder).getLines().toList
发布于 2014-09-22 23:03:39
scala源代码的解决方案(基于@Esailija的答案):
def toSource(inputStream:InputStream): scala.io.BufferedSource = {
import java.nio.charset.Charset
import java.nio.charset.CodingErrorAction
val decoder = Charset.forName("UTF-8").newDecoder()
decoder.onMalformedInput(CodingErrorAction.IGNORE)
scala.io.Source.fromInputStream(inputStream)(decoder)
}
https://stackoverflow.com/questions/13625024
复制相似问题