当前位置: 首页 > 面试题库 >

如何在Scala或Java中读取带有混合编码的文本文件?

李兴安
2023-03-14
问题内容

我正在尝试解析CSV文件,最好使用weka.core.converters.CSVLoader。但是,我拥有的文件不是有效的UTF-8文件。它主要是一个UTF-8文件,但是某些字段值使用不同的编码,因此没有一种编码方式可以使整个文件有效,但是无论如何我都需要对其进行解析。除了使用像Weka这样的Java库之外,我主要在Scala中工作。我什至无法读取scala.io中的文件。资料来源:例如

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为我指出正确的方向。这导致我转向如何检测非法的UTF-8字节序列以将其替换为java
inputstream?
它提供了核心的Java解决方案。在Scala中,我可以通过将编码解码器隐式设置为默认行为。我认为可以通过将隐式编解码器定义放在包对象中,使它成为整个包的默认行为。


问题答案:

这是我设法用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

hellö wörld在UTF-8中,其中混入了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)


 类似资料:
  • 问题内容: 我想读取一个包含空格分隔值的文本文件。值是整数。如何读取并将其放入数组列表? 这是文本文件内容的示例: 我想将它包含在arraylist中。如何用Java做到这一点? 问题答案: 你可以用来将文本文件的所有行都放入。 教程:基本文件读取,写入和创建文本文件 你可以用来基于正则表达式拆分部分。 教程:数字和字符串>字符串>操纵字符串中的字符 你可以使用将转换为。 教程:数字和字符串>字符

  • 问题内容: 我试图根据此方法的输出以UTF-8或Windows-1252格式读取文件: 到目前为止,我有: 我遇到的问题是将实例转换为。 此外: 文件本身的名称()不能被认为是特定的; 有时文件名将包含UTF-8字符,有时还包含Windows-1252。文件的内容也是如此(但是,如果文件名和文件内容 始终 具有匹配的字符集)。 只有内部的逻辑可以选择要应用的字符集,因此 在 调用此方法 之前 尝试

  • 我有一个源代码,它读取文本文件并存储到一个元组类型的向量中: 包含以下数据: 因此数据由空格+垂直线+空格(多重分隔符)分隔。 如何更改源代码以处理多个分隔符? 注意:如果数据仅用空格隔开,则程序可以工作。

  • 读取ArrayType值(phoneNumbers)时出错,没有ArrayType值,我可以读取其余值。 当我这样做时。show,它只显示列名,没有值,但当我不使用“phoneNumbers”数组时,它可以正常工作。

  • 问题内容: 尝试仅在文件包含数字和单词的地方读取双数字。到目前为止,我已经完成的代码可以从文件中正确读取并打印带有数字和单词的完整列表。不知道如何排除单词并打印只读的双精度数字。 问题答案: 这是一个工作测试 请注意,我使用了美国语言环境,以使扫描仪插入“。”作为小数点分隔符,在我的语言环境(默认)中为“,”。另请注意,nextDouble可以识别1.1和3(整数)

  • 问题内容: 我试图将文本文件加载到我的JavaScript文件中,然后从该文件中读取行以获取信息,我尝试使用FileReader,但它似乎无法正常工作。有人可以帮忙吗? 问题答案: 是的,可以使用FileReader,我已经做了一个示例,这是代码: 最后,我只是读了其他一些吸引我的答案,但正如他们所建议的那样,您可能正在寻找使您能够从JavaScript文件所在的服务器(或设备)加载文本文件的代码