Ответ 1
Вероятно, вы хотите иметь список поддерживаемых кодировок. Для каждого файла попробуйте каждую кодировку по очереди, возможно, начиная с UTF-8. Каждый раз, когда вы ловите MalformedInputException
, попробуйте следующую кодировку.
Я создаю простую программу 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
, который позволит мне читать текстовые файлы со многими различными типами символов?
Спасибо.
Вероятно, вы хотите иметь список поддерживаемых кодировок. Для каждого файла попробуйте каждую кодировку по очереди, возможно, начиная с UTF-8. Каждый раз, когда вы ловите MalformedInputException
, попробуйте следующую кодировку.
Создание 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)
Я также столкнулся с этим исключением с сообщением об ошибке,
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(путь, параметры)
Я написал следующее, чтобы распечатать список результатов для стандартного вывода на основе доступных кодировок. Обратите внимание, что он также сообщает вам, какая строка терпит неудачу из номера строки, основанной на 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);
}
}
ISO-8859-1 - это всеохватывающая кодировка, в том смысле, что она не должна бросать MalformedInputException. Так что это хорошо для отладки, даже если ваш вход не находится в этой кодировке. Итак: -
req.setCharacterEncoding("ISO-8859-1");
У меня были два символа с двумя правыми кавычками/двойными левыми кавычками на моем входе, и оба US-ASCII и UTF-8 бросили на них MalformedInputException, но ISO-8859-1 работал.
Ну, проблема в том, что Files.newBufferedReader(Path path)
выполняется следующим образом:
public static BufferedReader newBufferedReader(Path path) throws IOException {
return newBufferedReader(path, StandardCharsets.UTF_8);
}
так что в принципе нет смысла указывать UTF-8
, если вы не хотите быть описательным в своем коде.
Если вы хотите попробовать "более широкую" кодировку, вы можете попробовать с помощью StandardCharsets.UTF_16
, но вы не можете быть на 100% уверены, что все равно получите всевозможные символы.
вы можете попробовать что-то вроде этого или просто скопировать и пропустить ниже фрагмента.
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 ++;
}
}