Pull to refresh

Comments 53

А можно ссылку на оригинал: кем найдена причина падения и в чем она заключается? Вроде бы расследование еще не завершено пока…
Что сомнительно: вряд ли команды должны зависеть от кодировки (разве что туда проник автор статьи со своим «параметром -Dfile.encoding=UTF-32BE, чтобы уж наверняка».)
А то можно было бы сделать заголовок ещё лучше: «Java снова не тормозит» (если кто помнит про события 11-летной давности: «Робот под управлением Linux с софтом на Java убился об стену»).

А тем временем в Microsoft портировали проблему с кодировками из Java в powershell :)


Рекомендуемый всюду способ считывания xml-файлов:


 [xml]$xml = Get-Content Путь:\к\файлу.xml

При этом сначала считывается файл в системной кодировке, а потом превращается в DOM. А на то, что в самом файле может быть указана другая кодировка — не важно...

Get-Content — не специализированный коммандлет для работы с xml и он не ожидает указания кодировки от файла. Это просто получение содержимого, вся xml магия в приведении.
Вместе с тем, для Get-Content можно указать кодировку параметром -Encoding и не иметь проблем.

Это если кодировка файла — известна. А если нет?


Тот же XmlDocument, лежащий за синонимом [xml], умеет читать любой поток байт, определяя кодировку из декларации. Так же как XmlReader и XDocument.


Но в powershell эту возможность так просто использовать не получится — вот и гуляет ошибочное решение по интернету…

Ну, если это реально насущная проблема, можно прочитать первую строчку и сматчить из нее кодировку. PS же скриптовый язык и такие вещи тут на каждом углу, иначе получится очередной C# — за простоту и универсальность надо чем-то платить.

Это ж уже велосипед будет… Правильный способ — такой:


$xml = New-Object ([xml])
$xml.Load((Get-Item путь\к\файлу.xml))

Если путь абсолютный — то Get-Item не нужен


Проблема исключительно в том, что в инете советуют способ через Get-Content

Да, и правда лучше, спасибо.
Жуткий формат, я его избегаю постоянно, а тут упала задача как-раз в xml в 1251.
Они еще и в VC Runtime видимо портировали:

wcout << L"test" << endl; //будет выведено
wcout << L"тест" << endl; //не будет выведено
wcout << L"test" << endl; //НЕ будет выведено

Приходится делать заглушки с WriteConsoleW
Чтобы поработать с этим текстом в Java нам нужно загнать данные в String. Как это сделать?

Или еще вот так можно:
String str = new String(Files.readAllBytes(Paths.get("file")), StandardCharsets.UTF_8);
NASA широко использует Java, но только на наземных рабочих станциях, в частности для задач анализа и визуализации, но никто не будет её устанавливать непосредственно в аппараты. Так что громкий заголовок очень похож на случай так называемого вранья.

Там же все написано русским по белому! Java стоит не на аппарате, а в центре управления. Пруф конечно же все еще нужен — но ваше возражение совсем не по делу.

> Java стоит не на аппарате
Как же не на аппарате, если вы сами написали:
> Часть программного обеспечения для марсианского зонда Скиапарелли написали на Java

Или вы хотите улизнуть и сейчас скажете: «ну ПО то написали, но это не значит, что оно там используется!»

Во-первых, очевидно что имелась в виду та часть ПО, которая осталась на Земле. Во-вторых, пост писал не я.

При чем здесь Java, которая изначально задумывалась для полной поддержки Юникода, непонятно, ведь для Windows родная кодировка — UTF-16LE, начиная где-то с Windows 95, за 3 года до выхода 1-й Java.


У меня например консоль cmd.exe выдает:
H:\>chcp
Active code page: 437


Выводить кириллический текст в нее даже в UTF-8 бесполезно. При этом поставить правильную кодировку еще полдела, надо еще и шрифт поменять на TrueType.

Java оперирует внутри себя 16-битными Unicode сodepoint, но внешний мир жесток и несовершенен (особенно в Windows), поэтому статья правильно акцентирует внимание на том, что про кодировку помнить нужно и проставлять лучше явно. С другой стороны, на правильных операционных системах дефолтная кодировка в 99% работает корректно.

Консоль в винде всегда можно переключить в нужный режим. Кстати, начиная с win10 она даже последовательности VT100 поддерживает, если их включить...

Это очень хорошо. Осталось только определить, когда какой режим нужен, и кто его должен переключать.

В идеале, переключать должен был рантайм Java. При запуске или при первом обращении к консоли. И еще перед выходом — обратно.

Надо заметить, что, хотя проблема такая действительно существует, перечисленные в таблице методы — это легаси, существующее для совместимости (которая в мире java очень важна), а все новые api учитывают проблемы дефолтной кодировки и используют UTF8 в качестве кодировки по-умолчанию. Это хороший повод, например, использовать новый api для работы с файловой системой — там эти проблемы учтены, а для чтения файла в строку есть удобные методы, делающие это в одну строку кода.

Так о том и речь, что надо бы им @Deprecated поставить.

Но нет, они @Deprecated поставили именно на Date, который до сих пор никуда не делся и активно используется.
Беда в том, что этим легаси пользуются вовсю и даже в самом JDK. Привносят с этими методами ошибки туда, где их раньше не было.
Да, вероятно, было бы лучше, если бы такие потенциально опасные методы были помечены как @Deprecated. Но где их используют в JDK?
Например, вот здесь http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/4235be4c9432
ну да, но судя по тому, что этот код исправили и указали кодировку явно, это скорее баг, чем намеренно использование этого конструктора. И да, я согласен, что если бы они были @Deprecated, то такие ошибки отлавливать было бы намного проще.
> Найдена причина аварии
Хотя бы сменили бы желтушный заголовок, раз это лишь предположение. Мы ведь не «горячие новости» из smi2 тут читаем, а вполне адекватные посты.

Укажите примерно так:
> Откуда в Java всплывают проблемы с кодировками и возможная причина падения марсианского зонда
Статью можно резюмировать так: указывайте кодировку, передавая в соотв. методах параметр Charset — обычно StandardCharsets.UTF_8 хватает, на что указывают современные IDE (отдельное спасибо JetBrains за IDEA и анализатор «из коробки») и анализаторы типа FindBugs — благодаря им столько потенциальных багов было выявлено еще до тестирования!
UFO just landed and posted this here
Надо будет попробовать IDEA. В Eclipse пока не видел такого валидатора.

Ещё крайне полезно использовать forbidden-apis checker, умеет ловить следующее:


  • jdk-unsafe-* — использование методов jdk, которые неявно используют charset, locale или timezone по умолчанию;
  • jdk-deprecated-* — использование deprecated методов и jdk;
  • jdk-internal-* — использование внутренних методов jdk из пакетов, выдаваемых Security.getProperty("package.access");
  • jdk-non-portable — множество потенциально несовместимых api, включающее jdk-internal;
  • jdk-system-out — думаю и так ясно;
  • jdk-reflection — куски использования reflection, которые должны поломаться в java 9;
  • commons-io-unsafe-* — использование методов с default charset.

jdk-internal @openjdk 8u122
  • com.oracle.webservices.internal.
  • com.oracle.xmlns.internal.
  • com.sun.activation.registries.
  • com.sun.corba.se.
  • com.sun.imageio.
  • com.sun.istack.internal.
  • com.sun.jmx.
  • com.sun.media.sound.
  • com.sun.naming.internal.
  • com.sun.org.apache.bcel.internal.
  • com.sun.org.apache.regexp.internal.
  • com.sun.org.apache.xalan.internal.extensions.
  • com.sun.org.apache.xalan.internal.lib.
  • com.sun.org.apache.xalan.internal.res.
  • com.sun.org.apache.xalan.internal.templates.
  • com.sun.org.apache.xalan.internal.utils.
  • com.sun.org.apache.xalan.internal.xslt.
  • com.sun.org.apache.xalan.internal.xsltc.cmdline.
  • com.sun.org.apache.xalan.internal.xsltc.compiler.
  • com.sun.org.apache.xalan.internal.xsltc.trax.
  • com.sun.org.apache.xalan.internal.xsltc.util.
  • com.sun.org.apache.xerces.internal.
  • com.sun.org.apache.xml.internal.res.
  • com.sun.org.apache.xml.internal.security.
  • com.sun.org.apache.xml.internal.serializer.utils.
  • com.sun.org.apache.xml.internal.utils.
  • com.sun.org.apache.xpath.internal.
  • com.sun.org.glassfish.
  • com.sun.proxy.
  • com.sun.xml.internal.
  • jdk.internal.
  • jdk.nashorn.internal.
  • jdk.nashorn.tools.
  • oracle.jrockit.jfr.
  • org.jcp.xml.dsig.internal.
  • sun.

Естественно, можно добавлять свои сигнатуры.

И, кстати, поддержу: почему стандартная кодировка в винде не UTF-8, как в тех же линухах?
Когда «в тех же линухах» появилась UTF-8 как стандарт?
Когда в винде появился юникод?
Дело в том, что само понятие стандартной кодировки размыто. Одни программы работают в чистом ASCII, другие UTF-8, функции Win32 работают в UTF-16 или в Ansi. Консоль работает в OEM и легкоп переключается командой chcp. У cygwin своя система локализации. Вполне возможно, что в будущих версиях Windows кодировки могут быть у разных пользователей разные. Какую кодировку считать стандартной, непонятно.
А еще, мы тут на работе словили exception при JAXB анмаршаллинге xml, который приехал с BOM, это было очень весело править :)
Да. Это шутка. Я старался, чтобы было понятно. Загнал текст о марсианском зонде под спойлер. Но, видимо, перемудрил с заголовком.
Перед самой посадкой никакие команды на зонд не отправляются (пинг не позволяет), она проходит в автономном режиме.
Согласен. Перед посадкой что-либо отправлять на аппарат уже бесполезно. В процессе полета обычно производят коррекцию траектории командами с Земли. А посадка производится в полностью автоматическом режиме.
UFO just landed and posted this here
UFO just landed and posted this here
Это я добавил, чтобы было понятно, в каких условиях работает test case. Ведь установить кодировку по умолчанию изнутри программы невозможно, поэтому тест основывается на том, что его запускают в определенном окружении. Тестировщики, они ведь они такие: прогонят тест и напишут, что «не воспроизводится».
Видимо, это связано с тем, что в мир Java иммигрировали люди, не привыкшие решать проблему кодировок. Скажем, в C# по умолчанию применяется кодировка UTF-8, поэтому разработчик, переехавший с C#, вполне разумно считает, что InputStreamReader по умолчанию использует эту же кодировку, и не вдается в детали его реализации.

Java и C#, нужно смотреть контракт класса, который используешь.

В C# действительно при чтении файлов по умолчанию используется UTF8, или определяется по заголовку (для XML) или BOM, если заголовок не определен или отсутствует BOM.
Тем не менее, и тут есть вероятность ошибки автоматического определения кодировки.
А что, если BOM это BOM, а полезные данные? — при создании объекта-кодировки можно указать, использовать ли BOM, когда эта кодировка передается ридеру (и тут тоже есть свои умолчания — использовать BOM).
Поэтому программист тут тоже должен понимать, что именно делает, и принимать решение, что делать.

И в C# хватает своих неоднозначностей — например, использование глобальных настроек CurrentCulture при работе со строками.
Да, важная проблема. Я использовал тупо FileWriter, и при некоторых параметрах он писал китайские иероглифы.
Что характерно, в классе java.nio.Files, появившемся в java 7, по умолчанию используется UTF-8.
А в библиотеке Guava, в аналогичном классе Files, вообще нет методов, имеющих кодировку по умолчанию (например, Files.toString()).
«откуда в Java всплывают проблемы с кодировками» — почему то, что инженер не прочитал что АПИ, стало проблемой Java?
А еще в далеком 2005-ом году, когда робот Томми разбился об стену на гонках роботов, тоже говорили, что Java виновата:)
>Я считаю, что функции, зависящие от кодировки по умолчанию, надо обозначить устаревшими, тем более, что их не так уж и много

Если все начнут хардкодить кодировки, получится еще больший ацкий зоопарк, на который даже параметрами командной строки не повлиять. Просто кодировка по умолчанию должна быть не системная, а на всех платформах всегда и везде — UTF-8. Кому хочется легаси и экзотики — пускай передают параметры или хардкодят через предложенные методы, но в этом случае при каждом запуске приложения и каждом чтении файла должен выскакивать назойливый диалог: «вы используете устаревшую кодировку, настоятельно рекомендуем конвертировать ваши файлы в UTF-8».
> Например, так делали многие плагины к анту. Сам ант работал с file.encoding=UTF-8, но какой-нибудь генератор кода, вызываемый плагином, работал с кодировкой по умолчанию, и получалась обычная каша из разных кодировок.

1. окей гугл, исходники openjdk без регистрации.
2. окей, написать обертку для бинарники java, подставляющую нужные аргументы — не вариант?
3. если «не вариант» — тем же easyhook/LD_PRELOAD/%решениенейм% быстро запилить фильтр для запускающихся процессов с целью передачи нужных аргументов. Тем более что для Java на современных машинах под виндой приходится примерно таким образом «портить» обращение к функциям, возвращающим информацию о DPI дисплея ради некоторых древних приложений типа Packet Tracer.
А вот и официальный отчет из ESA (расследование еще не завершено):

When merged into the navigation system, the erroneous information generated an estimated altitude that was negative – that is, below ground level. This in turn successively triggered a premature release of the parachute and the backshell, a brief firing of the braking thrusters and finally activation of the on-ground systems as if Schiaparelli had already landed. In reality, the vehicle was still at an altitude of around 3.7 km.


Короче какой-то сенсор послал максимальное значение в компьютер и тот решил включить тормоза и отстрелить парашют.
FileWriter.FileWriter(..., Charset) не существуют, или я что-то упустил?
Sign up to leave a comment.

Articles

Change theme settings