Kwert-soft.ru

IT Софт для ПК
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Java string charset

Установка кодировки символов Java по умолчанию?

Как правильно установить кодировку символов по умолчанию, используемую JVM (1.5.х) программно?

Я читал, что -Dfile.encoding=whatever раньше был способ пойти для старых JVMs. У меня нет такой роскоши по причинам, в которые я не хочу вдаваться.

и свойство устанавливается, но это, похоже, не вызывает окончательный вызов getBytes ниже, чтобы использовать UTF8:

15 ответов

к сожалению, file.encoding свойство должно быть указано при запуске JVM; к моменту ввода основного метода кодировка символов, используемая String.getBytes() и конструкторы по умолчанию InputStreamReader и OutputStreamWriter постоянно кэшируется.

As Эдвард грех указывает, в частном случае, как это, переменная окружения JAVA_TOOL_OPTIONS can используется для указания этого свойства, но обычно это делается так это:

Charset.defaultCharset() будет отражать изменения file.encoding свойство, но большинство кода в основных библиотеках Java, которые должны определить кодировку символов по умолчанию, не используют этот механизм.

когда вы кодируете или декодируете, вы можете запросить file.encoding собственность или Charset.defaultCharset() чтобы найти текущую кодировку по умолчанию и использовать соответствующий метод или перегрузку конструктора, чтобы указать ее.

поскольку командная строка не всегда может быть доступна или изменена, например, во встроенных VMs или просто VMs, запущенных глубоко в сценариях, a JAVA_TOOL_OPTIONS переменная предоставляется так, что агенты могут быть запущены в этих случаях.

установив переменную среды (Windows) JAVA_TOOL_OPTIONS до -Dfile.encoding=UTF8 , (Java) System свойство будет устанавливаться автоматически при каждом запуске JVM. Вы будет знать, что параметр был выбран, потому что следующее сообщение будет опубликовано на System.err :

Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8

У меня есть хакерский способ, который определенно работает!!

таким образом, вы собираетесь обмануть JVM, который будет думать, что charset не установлен и сделать это, чтобы установить его снова в UTF-8, во время выполнения!

Я думаю, что лучший подход, чем установка набора символов платформы по умолчанию, тем более, что у вас, похоже, есть ограничения на влияние на развертывание приложения, не говоря уже о платформе, — это вызвать гораздо более безопасный String.getBytes(«charsetName») . Таким образом, ваше приложение не зависит от вещей, находящихся вне его контроля.

Я лично считаю, что String.getBytes() должно быть устаревшим, так как это вызвало серьезные проблемы в ряде случаев, которые я видел, когда разработчик не учитывал значение по умолчанию кодировка, возможно, меняется.

Я не могу ответить на ваш первоначальный вопрос, но я хотел бы предложить вам несколько советов-не зависите от кодировки JVM по умолчанию. Всегда лучше явно указать желаемую кодировку (например,» UTF-8″) в вашем коде. Таким образом, вы знаете, что он будет работать даже в разных системах и конфигурациях JVM.

Откуда в Java всплывают проблемы с кодировками и возможная причина падения марсианского зонда

Планета Марс уже не первый год населена роботами. То тут, то там появляются беспилотные электрокары и летающие дроны, а в программах, написанных на Java, с завидной регулярностью всплывают проблемы с кодировками.

Хочу поделиться своими мыслями о том, почему это происходит.

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

Обратите внимание, что для чтения файла недостаточно просто знать его имя. Нужно еще знать, в какой кодировке в нем находятся данные. Двоичное представление символов в памяти Java-машины и в файле на жестком диске практически никогда не совпадает, поэтому нельзя просто взять и скопировать данные из файла в строку. Сначала нужно получить последовательность байт, а уже потом произвести преобразование в последовательность символов. В приведенном примере это делает класс InputStreamReader.

Код получается достаточно громоздким при том, что необходимость в преобразовании из байтов в символы и обратно возникает очень часто. В связи с этим логичным было бы предоставить разработчику вспомомогательные функции и классы, облегчающие работу по перекодировке. Что для этого сделали разработчики Java? Они завели функции, которые не требуют указания кодировки. Например, класс InputStreamReader имеет конструктор с одним параметром типа InputStream.

Стало чуть попроще. Но здесь разработчики Java закопали серьезные грабли. В качестве кодировки для преобразования данных они использовали так называемый «default character encoding».

Default charset устанавливается Java-машиной один раз при старте на основании данных взятых из операционной системы и сохраняется для информационных целей в системном свойстве file.encoding. В связи с этим возникают следующие проблемы.

  1. Кодировка по умолчанию — это глобальный параметр. Нельзя установить для одних классов или функций одну кодировку, а для других — другую.
  2. Кодировку по умолчанию нельзя изменить во время выполнения программы.
  3. Кодировка по умолчанию зависит от окружения, поэтому нельзя заранее знать, какая она будет.
  4. Поведение методов, зависящих от кодировки по умолчанию, нельзя надежно покрыть тестами, потому что кодировок достаточно много, и множество их значений может расширяться. Может выйти какая-нибудь новая ОС с кодировкой типа UTF-48, и все тесты на ней окажутся бесполезными.
  5. При возникновении ошибок приходится анализировать больше кода, чтобы узнать, какую именно кодировку использовала та или иная функция.
  6. Поведение JVM в случае изменения окружения после старта становится непредсказуемо.

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

Из-за этого происходят удивительные вещи. Например, программа может неправильно открыть файл, который ранее сама же создала.

Или, скажем, есть у нас XML-файл, у которого в заголовке написано encoding=«UTF-8», но в Java-программе этот файл открывается при помощи класса FileReader, и привет. Где-то откроется нормально, а где-то нет.

Читать еще:  Java jdbc connection

Особенно ярко проблема file.encoding проявляется в Windows. В ней Java в качестве кодировки по умолчанию использует ANSI-кодировку, которая для России равна Cp1251. В самой Windows говорится, что «этот параметр задает язык для отображения текста в программах, не поддерживающих Юникод». При чем здесь Java, которая изначально задумывалась для полной поддержки Юникода, непонятно, ведь для Windows родная кодировка — UTF-16LE, начиная где-то с Windows 95, за 3 года до выхода 1-й Java.

Так что если вы сохранили при помощи Java-программы файл у себя на компьютере и отправили его вашему коллеге в Европу, то получатель при помощи той же программы может и не суметь открыть его, даже если версия операционной системы у него такая же как и у вас. А когда вы переедете с Windows на Mac или Linux, то вы уже и сами свои файлы можете не прочитать.

А ведь еще есть Windows консоль, которая работает в OEM-кодировке. Все мы наблюдали, как вплоть до Java 1.7 любой вывод русского текста в черном окне при помощи System.out выдавал крокозябры. Это тоже результат использования функций, основанных на default character encoding.

Я у себя проблему кодировок в Java решаю следующим образом:

  1. Всегда запускаю Java с параметром -Dfile.encoding=UTF-8. Это позволяет убрать зависимость от окружения, делает поведение программ детерминированным и совместимым с большинством операционных систем.
  2. При тестировании своих программ обязательно делаю тесты с нестандартной (несовместимой с ASCII) кодировкой по умолчанию. Это позволяет отловить библиотеки, которые пользуются классами типа FileReader. При обнаружении таких библиотек стараюсь их не использовать, потому что, во-первых, с кодировками обязательно будут проблемы, а во-вторых, качество кода в таких библиотеках вызывает серьезные сомнения. Обычно я запускаю java с параметром -Dfile.encoding=UTF-32BE, чтобы уж наверняка.

Это не дает стопроцентной гарантии от проблем, потому что есть же еще и лаунчеры, которые запускают Java в отдельном процессе с теми параметрами, которые считают нужными. Например, так делали многие плагины к анту. Сам ант работал с file.encoding=UTF-8, но какой-нибудь генератор кода, вызываемый плагином, работал с кодировкой по умолчанию, и получалась обычная каша из разных кодировок.

По идее, со временем код должен становиться более качественным, программы более надежными, форматы более стандартизованными. Однако этого не происходит. Вместо этого наблюдается всплеск ошибок с кодировками в Java-программах. Видимо, это связано с тем, что в мир Java иммигрировали люди, не привыкшие решать проблему кодировок. Скажем, в C# по умолчанию применяется кодировка UTF-8, поэтому разработчик, переехавший с C#, вполне разумно считает, что InputStreamReader по умолчанию использует эту же кодировку, и не вдается в детали его реализации.

Недавно наткнулся на подобную ошибку в maven-scr-plugin.

Но настоящее удивление пришлось испытать при переезде на восьмерку. Тесты показали, что проблема с кодировкой затесалась в JDK.

На девятке не воспроизводится, видимо, там уже починили.

Поискав по базе ошибок, я нашел еще одну недавно закрытую ошибку, связанную с теми же самыми функциями. И что характерно, их даже исправляют не совсем правильно. Коллеги забывают, что для стандартных кодировок, начиная с Java 7, следует использовать константы из класса StandardCharsets. Так что впереди, к сожалению, нас ждет еще масса сюрпризов.

Запустив grep по исходникам JDK, я нашел десятки мест, где используются платформозависимые функции. Все они будут работать некорректно в окружении, где родная кодировка, несовместима с ASCII. Например, класс Currency, хотя казалось бы, уж этот-то класс должен учитывать все аспекты локализации.

Когда некоторые функции начинают создавать проблемы, и для них существует адекватная альтернатива, давно известно, что нужно делать. Нужно отметить эти функции как устаревшие и указать, на что их следует заменить. Это хорошо зарекомендовавший себя механизм deprecation, который даже планируют развивать.

Я считаю, что функции, зависящие от кодировки по умолчанию, надо обозначить устаревшими, тем более, что их не так уж и много:

ФункцияНа что заменить
Charset.defaultCharset()удалить
FileReader.FileReader(String)FileReader.FileReader(String, Charset)
FileReader.FileReader(File)FileReader.FileReader(File, Charset)
FileReader.FileReader(FileDescriptor)FileReader.FileReader(FileDescriptor, Charset)
InputStreamReader.InputStreamReader (InputStream)InputStreamReader.InputStreamReader (InputStream, Charset)
FileWriter.FileWriter(String)FileWriter.FileWriter(String, Charset)
FileWriter.FileWriter(String, boolean)FileWriter.FileWriter(String, boolean, Charset)
FileWriter.FileWriter(File)FileWriter.FileWriter(File, Charset)
FileWriter.FileWriter(File, boolean)FileWriter.FileWriter(File, boolean, Charset)
FileWriter.FileWriter(FileDescriptor)FileWriter.FileWriter(FileDescriptor, Charset)
OutputStreamWriter.OutputStreamWriter (OutputStream)OutputStreamWriter.OutputStreamWriter (OutputStream, Charset)
String.String(byte[])String.String(byte[], Charset)
String.String(byte[], int, int)String.String(byte[], int, int, Charset)
String.getBytes()String.getBytes(Charset)

Да, а что там с космическим аппаратом на Марсе?

Часть программного обеспечения для марсианского зонда Скиапарелли написали на Java, на актуальной в то время версии 1.7. Запустили изделие весной, и путь к месту назначения составил полгода. Пока он летел, в Европейском космическом агентстве обновили JDK.

Ну а что? Разработка софта для нынешней миссии завершена, надо делать ПО уже для следующей, а мы все еще на семерке сидим. НАСА и Роскосмос уже давно на восьмерку перешли, а там лямбды, стримы, интерфейсные методы по умолчанию, новый сборщик мусора, и вообще.

Обновились и перед посадкой отправили на космический аппарат управляющую команду не в той кодировке, в которой он ожидал.

How to get and set default Character encoding or Charset in Java

Default Character encoding or Charset in Java

What is character encoding in Java

How to get Default character encoding in Java ?

How to set Default character encoding in Java ?

/java java HelloWorld

Code Example to Get and Set Default Character Encoding Java

9 comments :

Character Encoding so far looked little difficult to me but after reading this article I at least got to know that what is character encoding in Java and where does it get used and what issues it can cause if bytes encoded in one character set decoded on another charset. Thanks a lot

Читать еще:  Java net bindexception

January 27, 2012 at 12:05 AM Anonymous said.

Note that explicitly trying to set the «file.encoding» system property on the command line or via environment variables is not supported; this value is not respected by all the JVM’s APIs. See the evaluation comments on bugs.sun.com Bug > January 31, 2012 at 12:57 AM Javin @ substring in java said.

@Anonymous thanks for pointing it out. So do you see any alternative except providing character encoding explicitly on constructors ?

February 3, 2012 at 10:43 PM Anonymous said.

I need to write to files with their filenames may include the euro (€) character. I can do it in my own pc with ubuntu 10.04 and java 1.6.0.26 where by default java uses UTF-8. But when I execute the code in the server (where java defaults to ASCII) the filename have a ? character.
I use /usr/local/jdk1.6.0_10/bin/java — >
Can you help me with this? Thank you very much .

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

public class TestEuro <
public static void main( String[] args ) throws Exception <

System.out.println(«file.encoding: » + System.getProperty(«file.encoding»));
String path = «/srv/fws/java/indexer/» ;
String s1 = «test_€_encoding.txt» ;
File f = new File(path + s1);
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(f));
osw.write( «test filen» ) ;
osw.write( «€» + «n») ;
osw.write( «test file» ) ;
osw.flush();
osw.close();
System.out.println(«s1: » + s1);
>
>

March 1, 2012 at 1:27 AM Anonymous said.

I understand character encoding in Java hard way. We had Java program which reads xml file and also calls String.getBytes() to convert XML String to byte array, now this call is subject to character encoding. By default it uses system’s character encoding or value returned by System.getProperty(«file.encoding»), due to this for one input our program works fine in one of environment but failed in other environment. It took a lot of time to find out where is the issue. ultimately fix was to run your Java program with specified character encoding e.g. -Dfile.encoding=UTF-16, this will make sure that your application will always use correct character encoding and not behave differently on different machine.

I’ve got a number of files in an unknown encoding format. Does anyone here know of a tool that would display the results of multiple encoding assumptions converted to one common output format (such as UTF-8)? The tool would take an input string, then return an array (or display) multiple result strings, each with a different base assumption about the initial encoding? For example: convert string foo= «ç›£è¦–対象ã�®åœ°åŸŸã‚¯ãƒ©ã‚¹ã�®ä¸€è¦§» into UTF-8, assuming that foo is each of (UTF-8, EUC-JP, Shift-JIS, etc.).

October 11, 2013 at 10:59 AM Anonymous said.

Messing with character encoding is very difficult bug to solve. first of all if you don’t explicitly specifly character encoding to methods like String.getBytes() or new String(byte[]) , it wlll use platform’s default encoding, which could be diffeerent in differnet server and operating system. Default encoding may not be even sufficient to display all the characters your appliation is expecting e.g. your default encoding might be able to handle european characters but not the east asian characters.

PS: Default Character Encoding can be overwritten in your process as below.
InputStreamReader reader = new InputStreamReader(is, «UTF-8»);

Java 8 строки

В Java строки являются объектами класса java.lang.String, который является обычным классом но со специальной поддержкой компилятором. Этот класс представляет строку в виде набора символов UTF-16, где дополнительные символы представляются в виде суррогатных пар, другими словами один символ Юникода может состоять из двух char code unit. Индекс в строке адресует char code unit, а на символ. Дополнительные символы используют две позиции в строке.

char code unit — 16-битный символ char .

char code point — символ юникода. Может состоять из двух char -ов.

Такая путаница из char code unit и char code point произошла из-за того, что первоначально стандарт Юникода 1991 года предполагал 16-битные символы фиксированной длины, однако в последствии он был расширен в 1996 году для возможности представления символов, которым необходимо больше 16 бит.

Все строковые литералы в Java являются объектами класса String .

Примеры создания строк:

Для строковых литералов используются двойный кавычки, а для примитивного типа char — одинарные.

У класса String довольно много конструкторов. Можно, например, создать строку на основе массива байт:

В этих примерах «ISO-8859-1» — это имя кодировки.

Каждая реализация Java поддерживает следующие виды кодировок:

Дополнительно могут поддерживаться другие кодировки, например для Windows обязательно будет поддержка кодировки windows-1251.

Когда компилятор видит строковый литерал, например «Hello world!» , в коде, он создаёт объект класса java . lang . String .

Так как строковые литеры являются объектами, то у них можно вызывать методы:

В Java нет перегрузки операций, но класс строки имеет особую поддержку со стороны компилятора — строк можно соединять с помощью операции «+» (при этом используется java.lang.StringBuilder или java . lang . StringBuffer ):

Конкатенации строковых литералов вида » goes» + » to school.» компилятор вычисляет на этапе компиляции, поэтому во время выполнения не будет происходить лишних операций. Можно с помощью «+» разделять строковые константы на несколько строк, компилятор уберёт лишние операции сам и превратит всё в одну строковую литералу:

Каждый объект в Java может участвовать в операции конкатенации (соединения) строк, в этом случае используется метод toString ( ) , (если ссылка на объект равна null, то используется строка «null» ):

Выведет в консоль:

Класс String НЕ имеет специальной поддержки для == , поэтому сравнивать строки нужно либо через метод equals ( ) , либо equalsIgnoreCase ( ) , либо compareTo ( ) , либо compareToIgnoreCase ( ) .

Читать еще:  Java как возвести число в степень

В Java используется пул строковых литералов. Одинаковые строковые литералы всегда ссылаются на один и тот же экземпляр класса String :

Этот код выведет:

  1. Одинаковые строковые литералы всегда ссылаются на один и тот же экземпляр класса String .
  2. Экземпляры классы String , вычисленные во время выполнения, создаются заново, автоматически в пуле не участвуют и потому различны.
  3. Строковые литералы в константных выражениях вычисляются на этапе компиляции и затем расцениваются как обычные литералы.
  4. С помощью метода intern() можно добавить строку в пул либо получить ссылку на такую строку из пула.

Многие методы строки принимают в качестве параметра или возвращают в качестве результата индекс. Индексация начинается с нуля. Первый char (имеется в виду char code unit, а не символ, разумеется) в строке имеет индекс 0, а последний имеет индекс length() — 1. Если переданный в параметр индекс выходит за пределы строки, то методы генерируют исключение java . lang . IndexOutOfBoundsException .

Некоторые методы принимают в качестве параметров начальный индекс и конечный индекс. В этом случае начальный индекс включается в отрезок, а конечный индекс исключается, так что длина отрезка получается равной конечный индекс минус начальный индекс, как на картинке.

Подобная индексация является стандартом в Java. Всегда когда указывается отрезок в массиве, строке, списке или ещё-где-то, начальный индекс включается в отрезок, а конечный исключается.

Методы класса java . lang . String

Возвращает char (Unicode code unit) по указанному индексу.

Возвращает символ (Unicode code point) по указанному индексу. Индекс указывается для char -ов.

Лексикографическое сравнение строк. Возвращает -1, если текущая строка лексикографически меньше anotherString , 0 — строки лексикографически равны, 1 — текущая строка лексикографически больше. Метод полезен для сортировки строк.

Лексикографическое сравнение, игнорирующее разницу в регистрах букв.

Если длина строки str равна 0, то возвращает this , иначе возвращает строку, являющуюся конкатенацией (объединением) текущей строки и str .

Возвращает true , если текущая строка содержит последовательность символов s . Класс java . lang . String реализует интерфейс java . lang . CharSequence , так что в качестве параметра можно передавать экземпляр класса String .

Возвращает true , если текущая строка заканчивается на suffix или равна ему. Если suffix является пустой строкой, то возвращает true .

Возвращают массив байт, содержащий строку в указанной кодировке.

Возвращает индекс первого вхождения символа ch , начиная с fromIndex . Если символ не найден, то возвращает -1.

public int indexOf ( String str )

Возвращает индекс первого вхождения подстроки в строке, начиная с fromIndex . Если подстрока не найдена, то возвращает -1.

Форматированный вывод. Более подробно будет рассмотрен в статье про форматирование.

Магический метод. В Java существует пул строк. Этот метод проверяет наличие строки в пуле, если в пуле есть такая строка, то метод возвращает ссылку на неё. Если в пуле нет такой строки, то строка добавляется в пул, и возвращается ссылка на неё. Все строковые литералы и константы автоматически включаются в пул. Примеры:

Объединяет несколько CharSequence в одну строку, используя в качестве разделителя delimiter .

Возвращает длину строки в char -ах (Unicode code units). Количество символов в строке (Unicode code points) может отличаться от этого значения.

Возвращает true , если length ( ) == 0 .

Возвращает строку, в которой все oldChar заменены на newChar . Если oldChar в строке нет, то возвращается исходная строка.

Возвращает строку, в которой все вхождения подстрок согласно регулярному выражению заменены на replacement .

Возвращает строку, в которой все вхождения последовательности символов target заменены на replacement .

Возвращает подстроку, начинающуюся с beginIndex (включительно) до endIndex (исключительно) или конца строки.

Разбивает строку на массив строк по регулярному выражению. Пустые конечные строки не включаются в результирующий массив.

Возвращает true , если строка начинается с prefix либо равна ему. Если prefix является пустой строкой, то возвращается true .

Возвращает строку, где все символы приведены в нижний регистр относительно текущей локали или указанной.

Возвращает строку, где все символы приведены в верхний регистр относительно текущей локали или указанной.

Возвращает строку, в которой убраны пробелы в начале и в конце строки. Если строка начинается и заканчивается на непробельные символы (больше ‘u0020’ ), то возвращается ссылка на this .

Возвращает строковое представление объекта. В случае с Object результатом является obj . toString ( ) , если obj ! = null и «null» в противном случае.

и другие методы.

java.lang.StringBuilder

В отличие от String класс StringBuilder позволяет менять содержимое своих экземпляров. В большинстве случаев нужно использовать String , использование же StringBuilder целесообразно в случаях, когда вам нужно соединить большое количество строковых переменных, например перебирая элементы массива или коллекции в цикле.

Так же как и у String у StringBuilder есть метод length ( ) , позволяющий узнать его длину в char -ах.

В отличие от String у StringBuilder кроме длины есть ещё вместимость/ёмкость (capacity). Вместительность можно узнать с помощью метода capacity ( ) , она всегда больше или равна длине.

StringBuilder ( )
Создаёт пустой StringBuilder вместительностью 16 (16 пустых элементов).
StringBuilder ( CharSequence cs )Создаёт StringBuilder , содержащий символы из последовательности и 16 дополнительных пустых элементов.
StringBuilder ( int initCapacity )Создаёт пустой StringBuilder с начальной вместительностью в initCapacity элементов.
StringBuilder ( String s )Создаёт StringBuilder , который содержит указанную строку и 16 дополнительных пустых элементов.

StringBuilder содержит пару дополнительных методов, связанных с длиной, которых нет в String :

Длина и вместительность

МетодОписание
void setLength ( int newLength )Устанавливает длину последовательности символов. Если newLength меньше length ( ) , то последние символы обрезаются. Если newLength больше length ( ) , то в конец последовательности добавляются нулевые символы.
void ensureCapacity ( int minCapacity )Обеспечивает, что вместительность будет как минимум равной minCapacity .

Некоторые методы могут увеличить длину последовательности символов в StringBuilder . Если после выполнения подобного метода длина результирующей последовательности окажется больше вместительности, то вместительность автоматически увеличится.

Ссылка на основную публикацию
Adblock
detector