Подтвердить что ты не робот

All inclusive Charset, чтобы избежать "java.nio.charset.MalformedInputException: длина ввода = 1"?

Я создаю простую программу wordcount в Java, которая читает файлы в текстовом формате каталога.

Однако я продолжаю получать ошибку:

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, который позволит мне читать текстовые файлы со многими различными типами символов?

Спасибо.

4b9b3361

Ответ 1

Вероятно, вы хотите иметь список поддерживаемых кодировок. Для каждого файла попробуйте каждую кодировку по очереди, возможно, начиная с UTF-8. Каждый раз, когда вы ловите MalformedInputException, попробуйте следующую кодировку.

Ответ 2

Создание BufferedReader из Files.newBufferedReader

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)

Ответ 3

Я также столкнулся с этим исключением с сообщением об ошибке,

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");

Эта строка имеет длину 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 = 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 для записи любых строк. Это странная ошибка, возникающая в BufferedWriter, созданная из java.nio.file.Files.newBufferedWriter(путь, параметры)

Ответ 4

Я написал следующее, чтобы распечатать список результатов для стандартного вывода на основе доступных кодировок. Обратите внимание, что он также сообщает вам, какая строка терпит неудачу из номера строки, основанной на 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);
        }
    }

Ответ 5

ISO-8859-1 - это всеохватывающая кодировка, в том смысле, что она не должна бросать MalformedInputException. Так что это хорошо для отладки, даже если ваш вход не находится в этой кодировке. Итак: -

req.setCharacterEncoding("ISO-8859-1");

У меня были два символа с двумя правыми кавычками/двойными левыми кавычками на моем входе, и оба US-ASCII и UTF-8 бросили на них MalformedInputException, но ISO-8859-1 работал.

Ответ 6

Ну, проблема в том, что Files.newBufferedReader(Path path) выполняется следующим образом:

public static BufferedReader newBufferedReader(Path path) throws IOException {
    return newBufferedReader(path, StandardCharsets.UTF_8);
}

так что в принципе нет смысла указывать UTF-8, если вы не хотите быть описательным в своем коде. Если вы хотите попробовать "более широкую" кодировку, вы можете попробовать с помощью StandardCharsets.UTF_16, но вы не можете быть на 100% уверены, что все равно получите всевозможные символы.

Ответ 7

вы можете попробовать что-то вроде этого или просто скопировать и пропустить ниже фрагмента.

    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 ++;
        }
    }