全包式Charset避免" java.nio.charset.MalformedInputException:输入长度= 1"?

时间:2014-10-08 23:41:33

标签: java character-encoding

我用Java创建一个简单的wordcount程序,读取目录的基于文本的文件。

但是,我一直在收到错误:

java.nio.charset.MalformedInputException: Input length = 1

来自这行代码:

BufferedReader reader = Files.newBufferedReader(file,Charset.forName("UTF-8"));

我知道我可能会得到这个,因为我使用的Charset没有包含文本文件中的某些字符,其中一些包含其他语言的字符。但我想包括那些角色。

我后来在JavaDocs了解到Charset是可选的,仅用于更有效地读取文件,因此我将代码更改为:

BufferedReader reader = Files.newBufferedReader(file);

但有些文件仍会抛出MalformedInputException。我不知道为什么。

我想知道是否有一个包罗万象的Charset允许我阅读包含许多不同类型字符的文字文件

感谢。

10 个答案:

答案 0 :(得分:54)

您可能希望获得支持的编码列表。对于每个文件,依次尝试每个编码,可能以UTF-8开头。每次捕获MalformedInputException时,请尝试下一个编码。

答案 1 :(得分:23)

从Files.newBufferedReader创建BufferedReader

Files.newBufferedReader(Paths.get("a.txt"), StandardCharsets.UTF_8);

运行应用程序时,可能会抛出以下异常:

java.nio.charset.MalformedInputException: Input length = 1

但是

new BufferedReader(new InputStreamReader(new FileInputStream("a.txt"),"utf-8"));

效果很好。

不同的是,前者使用CharsetDecoder默认动作。

  

格式错误输入和不可映射字符错误的默认操作是报告

而后者使用REPLACE操作。

cs.newDecoder().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE)

答案 2 :(得分:16)

ISO-8859-1是一个包罗万象的字符集,从某种意义上说它保证不会抛出MalformedInputException。因此,即使您的输入不在此charset中,它也适用于调试。所以: -

import requests
from bs4 import BeautifulSoup

url = "https://twitter.com/realDonaldTrump?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor"

r = requests.get(url)

soup = BeautifulSoup(r.content, "html.parser")

links = soup.find_all("a")

g_data = soup.find_all("div", {"class": "content"})  

n_data = soup.find_all("strong", {"class": "fullname show-popup-with-id "})

c_data = soup.find_all("p", {"class": "TweetTextSize TweetTextSize--normal js-tweet-text tweet-text"})

for item in g_data:

    try:

        print(item.contents[0].find_all(n_data)[0].text)

    except:

        pass

我的输入中有一些双右引号/双引号字符,US-ASCII和UTF-8都对它们抛出MalformedInputException,但ISO-8859-1有效。

答案 3 :(得分:4)

我也遇到了这个带有错误消息的异常,

java.nio.charset.MalformedInputException: Input length = 1
at java.nio.charset.CoderResult.throwException(Unknown Source)
at sun.nio.cs.StreamEncoder.implWrite(Unknown Source)
at sun.nio.cs.StreamEncoder.write(Unknown Source)
at java.io.OutputStreamWriter.write(Unknown Source)
at java.io.BufferedWriter.flushBuffer(Unknown Source)
at java.io.BufferedWriter.write(Unknown Source)
at java.io.Writer.write(Unknown Source)

发现尝试使用

时发生了一些奇怪的错误
BufferedWriter writer = Files.newBufferedWriter(Paths.get(filePath));

从类中的泛型类型中编写字符串“orazg 54”。

//key is of generic type <Key extends Comparable<Key>>
writer.write(item.getKey() + "\t" + item.getValue() + "\n");

此String的长度为9,包含具有以下代码点的字符:

111 114 97 122 103 9 53 52 10

但是,如果类中的BufferedWriter替换为:

FileOutputStream outputStream = new FileOutputStream(filePath);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));

它可以成功编写此String而不会出现异常。另外,如果我从字符中创建相同的字符串创建它仍然可以正常工作。

String string = new String(new char[] {111, 114, 97, 122, 103, 9, 53, 52, 10});
BufferedWriter writer = Files.newBufferedWriter(Paths.get("a.txt"));
writer.write(string);
writer.close();

以前,在使用第一个BufferedWriter编写任何字符串时,我从未遇到任何异常。从java.nio.file.Files.newBufferedWriter(路径,选项)创建的BufferedWriter发生了一个奇怪的错误

答案 4 :(得分:4)

ISO_8859_1为我工作!我正在读取带有逗号分隔值的文本文件

答案 5 :(得分:1)

我编写了以下内容,根据可用的字符集将结果列表打印到标准输出。请注意,它还会告诉您哪个行从基于0的行号失败,以防您解决导致问题的字符。

public static void testCharset(String fileName) {
    SortedMap<String, Charset> charsets = Charset.availableCharsets();
    for (String k : charsets.keySet()) {
        int line = 0;
        boolean success = true;
        try (BufferedReader b = Files.newBufferedReader(Paths.get(fileName),charsets.get(k))) {
            while (b.ready()) {
                b.readLine();
                line++;
            }
        } catch (IOException e) {
            success = false;
            System.out.println(k+" failed on line "+line);
        }
        if (success) 
            System.out.println("*************************  Successs "+k);
    }
}

答案 6 :(得分:0)

嗯,问题是ssh: connect to host github.com port 22: Operation timed out fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. 是这样实现的:

Files.newBufferedReader(Path path)

所以基本上没有必要指定public static BufferedReader newBufferedReader(Path path) throws IOException { return newBufferedReader(path, StandardCharsets.UTF_8); } ,除非你想在你的代码中描述。 如果你想尝试一个“更广泛”的字符集你可以尝试使用UTF-8,但你无法100%确定能够获得所有可能的角色。

答案 7 :(得分:0)

尝试这个..我有同样的问题,下面的实现对我有用

Reader reader = Files.newBufferedReader(Paths.get(<yourfilewithpath>), StandardCharsets.ISO_8859_1);

然后在任何你想要的地方使用Reader。

foreg:

CsvToBean<anyPojo> csvToBean = null;
    try {
        Reader reader = Files.newBufferedReader(Paths.get(csvFilePath), 
                        StandardCharsets.ISO_8859_1);
        csvToBean = new CsvToBeanBuilder(reader)
                .withType(anyPojo.class)
                .withIgnoreLeadingWhiteSpace(true)
                .withSkipLines(1)
                .build();

    } catch (IOException e) {
        e.printStackTrace();
    }

答案 8 :(得分:0)

UTF-8适用于波兰字符

答案 9 :(得分:-2)

你可以尝试这样的事情,或者只是复制并经过下面的部分。

boolean exception = true;
Charset charset = Charset.defaultCharset(); //Try the default one first.        
int index = 0;

while(exception) {
    try {
        lines = Files.readAllLines(f.toPath(),charset);
          for (String line: lines) {
              line= line.trim();
              if(line.contains(keyword))
                  values.add(line);
              }           
        //No exception, just returns
        exception = false; 
    } catch (IOException e) {
        exception = true;
        //Try the next charset
        if(index<Charset.availableCharsets().values().size())
            charset = (Charset) Charset.availableCharsets().values().toArray()[index];
        index ++;
    }
}