Открываю файл блокнотом, пишу там: «ą» сохранить и закрыть.
Я пытаюсь прочитать этот файл двумя способами
Первый:
InputStream inputStream = Files.newInputStream(Paths.get("file.txt"));
int result = inputStream.read();
System.out.println(result);
System.out.println((char) result);
196 Ä
Второй:
InputStream inputStream = Files.newInputStream(Paths.get("file.txt"));
Reader reader = new InputStreamReader(inputStream);
int result = reader.read();
System.out.println(result);
System.out.println((char) result);
261 ą
Вопросов: 1) В двоичном режиме эта буква сохраняется как 196? Почему не как 261? 2) Это письмо сохраняется как 196 в какой кодировке?
Я пытаюсь понять, почему есть различия
Блокнот ++ показывает «utf-8 без бомбы», но я не вижу в таблице utf-8 буквы «ą» с кодом: 196




Вы получаете значение decimal букв LATIN
Вам необходимо savefile со стандартом кодирования UTF-8.
Убедитесь, что читаете их с похожими стандартами.
0x0105 261 LATIN SMALL LETTER A WITH OGONEK ą
0x00C4 196 LATIN CAPITAL LETTER A WITH DIAERESIS �
Обратитесь к этому: -https://www.ssec.wisc.edu/~tomw/java/unicode.html
ОП уже знает об этом. Итак, он не это имел в виду.
Попробуйте использовать InputStreamReader с кодировкой UTF-8, которая соответствует кодировке, используемой для записи файла из Notepad ++:
// this will use UTF-8 encoding by default
BufferedReader in = Files.newBufferedReader(Paths.get("file.txt"));
String str;
if ((str = in.readLine()) != null) {
System.out.println(str);
}
in.close();
У меня нет точного / воспроизводимого ответа на вопрос, почему вы видите результат, который видите, но если вы читаете с неправильной кодировкой, вы не обязательно увидите то, что сохранили. Например, если одиночный символ ą был закодирован двумя байтами, но вы читали его как ASCII, тогда вы могли бы получить обратно два символа, которые не соответствовали бы вашему исходному файлу.
Символ ą кодируется до двух байтов (C4 85), при этом C4 представляет собой 196 в десятичной системе счисления. Так что они действительно читают только первый байт.
@ TiiJ7 Спасибо за детективную работу. Я бы не знал, как это понять, но проблема с кодировкой - это первое, что бросилось мне в глаза :-)
Поскольку вы читаете эти две буквы в разных кодировках, вы можете проверить свою кодировку через InputStreamReader::getEncoding.
String s = "ą";
char iso_8859_1 = new String(s.getBytes(), "iso-8859-1").charAt(0);
char utf_8 = new String(s.getBytes(), "utf-8").charAt(0);
System.out.println((int) iso_8859_1 + " " + iso_8859_1);
System.out.println((int) utf_8 + " " + utf_8);
На выходе
196 Ä
261 ą
UTF-8 кодирует значения из диапазона U+0080 - U+07FF как два байта в форме 110xxxxx10xxxxxx (подробнее см. В вики). Таким образом, для значения доступны только 11 байт xxxxx xxxxxx.
ą - это индексируется как U + 0105, где 0105 - шестнадцатеричное значение (как десятичное - 261). В двоичном виде это можно представить как
01 05 (hex)
00000001 00000101 (bin)
xxx xxxxxxxx <- values for U+0080 - U+07FF range encode only those bits
001 00000101 <- which means `x` will be replaced by only this part
Таким образом, кодировка UTF-8 добавит маску 110xxxxx10xxxxxx, что означает, что она объединит
110xxxxx 10xxxxxx
00100 000101
в (два байта):
11000100 10000101
Теперь InputStream читает данные как сырые байты. Итак, когда вы звоните в inputStream.read(); в первый раз, вы получаете 11000100, который в десятичном виде является 196. Повторный вызов inputStream.read(); вернет 10000101, который является 133 в десятичном виде.
Reader были введены в Java 1.1, поэтому мы могли избежать такого беспорядка в нашем коде. Вместо этого мы можем указать, какую кодировку должен использовать Reader (или позволить ему использовать значение по умолчанию), чтобы получить правильно закодированные значения, как в этом случае 00000001 00000101 (без маски), который равен 0105 в шестнадцатеричной форме и 261 в десятичной форме.
Коротко
Reader (с правильно заданной кодировкой), если вы хотите читать данные как текст,Streams, если вы хотите читать данные как необработанные байты.
В какой кодировке вы сохранили свой односимвольный файл в Блокноте?