Налаштування кодування символів Java за замовчуванням


362

Як правильно встановити кодування символів за замовчуванням, яке програмно використовується JVM (1.5.x)?

Я читав, що -Dfile.encoding=whateverраніше був шлях до старших СВМ. У мене немає такої розкоші з причин, в які я не хочу потрапити.

Я намагався:

System.setProperty("file.encoding", "UTF-8");

І властивість встановлюється, але, схоже, не викликає кінцевий getBytesдзвінок нижче для використання UTF8:

System.setProperty("file.encoding", "UTF-8");

byte inbytes[] = new byte[1024];

FileInputStream fis = new FileInputStream("response.txt");
fis.read(inbytes);
FileOutputStream fos = new FileOutputStream("response-2.txt");
String in = new String(inbytes, "UTF8");
fos.write(in.getBytes());

Чудові коментарі, хлопці - і речі, про які я вже думав сам. На жаль, є базовий виклик String.getBytes (), над яким я не маю ніякого контролю. Єдиний спосіб, яким я зараз бачу його обійти, - це програмно встановити кодування за замовчуванням. Будь-які інші пропозиції?

6
може бути ірелевантним питанням, але чи є різниця, коли для UTF8 встановлено значення "UTF8", "UTF-8" або "utf8". Нещодавно я виявив, що контейнери IBM WAS 6.1 EJB і WEB по-різному розглядають рядки (у формі чутливості до регістру), що використовуються для визначення кодування.
igor.beslic

5
Просто деталь, але: віддайте перевагу UTF-8, ніж UTF8 (тільки перший є стандартним). Це все ще стосується 2012 року ...
Крістоф Руссі

4
Налаштування чи читання file.encodingвластивості не підтримується .
McDowell

@erickson Am досі не зрозумілий із запитом. Чи не правда, що "file.encoding" є релевантним, коли використовуються потоки вводу / виводу на основі символів (усі підкласи class Reader& class Writer)? Оскільки class FileInputStreamпотік вводу / виводу на основі байтів, то чому б слід дбати про набір символів у потоці вводу / виводу на байті?
переоблік

Відповіді:


311

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

Як зазначає Едуард Греч, у спеціальному випадку, подібному до цього, змінна середовища JAVA_TOOL_OPTIONS може бути використана для визначення цього властивості, але зазвичай це робиться так:

java -Dfile.encoding=UTF-8  com.x.Main

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

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


9
Для повноти хотілося б додати, що за допомогою трохи хитрощів ви можете дістатись до фактично використовуваного кодування за замовчуванням (як це кешовано) завдяки Gary Cronin: byte [] byteArray = {'a'}; InputStream inputStream = новий ByteArrayInputStream (byteArray); InputStreamReader Reader = новий InputStreamReader (inputStream); Рядок defaultEncoding = reader.getEncoding (); Список.xcf.berkeley.edu/lists/advanced-java/1999-O жовтня/…
Stijn de Witt

2
У JDK-4163515 є додаткова інформація про налаштування file.encodingсистемної програми після запуску JVM.
Каспар

2
Я чухав голову, тому що команда не працює на Windows, Linux та Mac ідеально ... тоді я поставив "навколо значення, як це: java -D" file.encoding = UTF-8 "
-jar

перевірити мою відповідь у випадку весняного завантаження Java: stackoverflow.com/a/48952844/986160
Michail Michailidis

170

З документації по інтерфейсу інструменту JVM ™

Оскільки до командного рядка не завжди можна отримати доступ чи модифікувати, наприклад, у вбудованих VM або просто VM, запущених глибоко в скриптах, надається JAVA_TOOL_OPTIONSзмінна, щоб агенти могли бути запущені в цих випадках.

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

Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8


Чи знаєте ви, що заява "Зібрано ..." буде надруковано в журналах Tomcat?
thatidiotguy

1
Привіт, Едвард Греч, я дякую за ваше рішення. Це було вирішено моєю проблемою в іншому дописі на форумі. stackoverflow.com/questions/14814230/…
Smaug

8
UTF8або UTF-8?
Крихітні

1
@Tiny Java розуміє і те, і інше. stackoverflow.com/questions/6031877 / ...
DLight

Ваше рішення врятувало мій час, велике спасибі !!
Собхан

67

У мене є гакітний спосіб, який безумовно працює !!

System.setProperty("file.encoding","UTF-8");
Field charset = Charset.class.getDeclaredField("defaultCharset");
charset.setAccessible(true);
charset.set(null,null);

Таким чином, ви збираєтеся обдурити JVM, який би подумав, що гарнітура не встановлена, і змусить її встановити її знову на UTF-8 під час виконання!


2
NoSuchFieldException для мене
SparK

10
Щоб злом працював, потрібно припустити, що менеджер безпеки вимкнено. Якщо у вас немає способу встановити прапор JVM, можливо, ви (можливо) також увімкнули систему керування безпекою.
Йонатан

3
JDK9 більше не схвалює цей злом. WARNING: An illegal reflective access operation has occurred • WARNING: Illegal reflective access by [..] • WARNING: Please consider reporting this to the maintainers of [..] • WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations • WARNING: All illegal access operations will be denied in a future release
dotwin

1
@Enerccio: Це не гарна відповідь, це брудний злом і проблема, яка чекає, що станеться. Це слід використовувати лише як надзвичайний захід.
sleske

1
@Enerccio: Сперечається, чи має "Java" мати спосіб встановити це - можна також стверджувати, що розробники "повинні" чітко вказувати кодування, коли це доречно. У будь-якому випадку це рішення може стати причиною серйозних проблем у довгостроковій перспективі, отже, застереження "лише для екстреного використання". На насправді, навіть використання аварійного сумнівна, тому що це підтримується спосіб зробити це, встановивши JAVA_TOOL_OPTIONS , як описано в іншому відповіді.
sleske

38

Я думаю, що кращим підходом, ніж встановлення набору символів платформи за замовчуванням, тим більше, що, здається, у вас є обмеження на вплив розгортання програми, не кажучи вже про платформу, - це називати набагато безпечнішим String.getBytes("charsetName"). Таким чином ваша програма не залежить від речей, що не є її контролем.

Я особисто вважаю, що це String.getBytes()слід застаріти, оскільки це спричиняло серйозні проблеми у ряді випадків, коли розробник не враховував можливі зміни шаблону за замовчуванням.


18

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


7
За винятком, звичайно, якщо ви пишете настільний додаток і обробляєте текст, визначений користувачем, який не має метаданих кодування - тоді кодування платформи за замовчуванням - найкраща здогадка про те, що може використовувати користувач.
Майкл Боргвардт

@MichaelBorgwardt "тоді кодування платформи за замовчуванням - найкраща здогадка", ти, здається, радиш, що бажати змінити типовий стан не є такою хорошою ідеєю. Ви хочете сказати, використовуйте явне кодування, коли це можливо, використовуючи наданий dafault, коли нічого іншого неможливо?
Raedwald

1
@Raedwald: так, це я мав на увазі. Кодування платформи за замовчуванням - це (принаймні, на машині кінцевого користувача) те, що зазвичай використовують користувачі в локальній системі, яку система встановлює. Це інформація, яку ви повинні використовувати, якщо у вас немає кращої (тобто конкретної документації) інформації.
Майкл Боргвардт

1
@MichaelBorgwardt Дурниця. Використовуйте бібліотеку для автоматичного виявлення кодування входу та збережіть його як Unicode з BOM. Це єдиний спосіб боротьби з кодуванням пекла.
Олександр Дубінський

Я думаю, що ви двоє не на одній сторінці. Майкл говорить про розшифровку, тоді як Raedwald ви говорите про обробку після розшифровки.
WesternGun


5

У нас були ті самі проблеми. Ми методично спробували кілька пропозицій з цієї статті (та інших) безрезультатно. Ми також спробували додати -Dfile.encoding=UTF8і, здавалося, нічого не працює.

Для людей, які відчувають цю проблему, в наступній статті , нарешті , допомогла нам вистежити описує , як регіональні настройки можуть привести до поломки unicode/UTF-8вJava/Tomcat

http://www.jvmhost.com/articles/locale-breaks-unicode-utf-8-java-tomcat

Налаштування локалу у ~/.bashrcфайлі працювало на нас.


4

Я спробував багато речей, але зразок коду тут працює ідеально. Посилання

Суть коду:

String s = "एक गाव में एक किसान";
String out = new String(s.getBytes("UTF-8"), "ISO-8859-1");

4

Якщо ви використовуєте Spring Boot і хочете передати аргумент file.encodingу JVM, вам слід запустити його так:

mvn spring-boot:run -Drun.jvmArguments="-Dfile.encoding=UTF-8"

це було нам потрібно, оскільки ми використовували JTwigшаблони, і операційна система, ANSI_X3.4-1968що ми з'ясувалиSystem.out.println(System.getProperty("file.encoding"));

Сподіваюся, це допоможе комусь!


2

Я використовую Elastic Beanstalk Amazon (AWS) і успішно змінив його на UTF-8.

У програмі Elastic Beanstalk перейдіть до розділу Конфігурація> Програмне забезпечення та "Властивості середовища". Додати (ім'я) JAVA_TOOL_OPTIONS за допомогою (значення) -Dfile.encoding = UTF8

Після збереження середовище перезапуститься з кодуванням UTF-8.


1

Не зрозуміло, чим ти займаєшся, і не маєш контролю над цим. Якщо ви можете вставити інший клас OutputStream у файл призначення, ви можете використовувати підтип OutputStream, який перетворює рядки в байти під встановленою вами схемою, скажімо, за замовчуванням UTF-8. Якщо модифікований UTF-8 є достатнім для ваших потреб, ви можете використовувати DataOutputStream.writeUTF(String):

byte inbytes[] = new byte[1024];
FileInputStream fis = new FileInputStream("response.txt");
fis.read(inbytes);
String in = new String(inbytes, "UTF8");
DataOutputStream out = new DataOutputStream(new FileOutputStream("response-2.txt"));
out.writeUTF(in); // no getBytes() here

Якщо такий підхід неможливий, він може допомогти, якщо ви уточните тут, що саме ви можете, а що не можете контролювати з точки зору потоку даних та середовища виконання (хоча я знаю, що це іноді простіше сказати, ніж визначити). Удачі.


5
DataInputStream і DataOutputStream - це класи спеціального призначення, які ніколи не повинні використовуватися з текстовими файлами із звичайним текстом. Модифікований UTF-8, який вони використовують, не сумісний з реальним UTF-8. Крім того, якщо ОП може використовувати ваше рішення, він також може використовувати правильний інструмент для цієї роботи: OutputStreamWriter.
Алан Мур

1
mvn clean install -Dfile.encoding=UTF-8 -Dmaven.repo.local=/path-to-m2

Команда працювала з exec-maven-plugin, щоб вирішити наступну помилку під час налаштування завдання jenkins.

Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512m; support was removed in 8.0
Error occurred during initialization of VM
java.nio.charset.IllegalCharsetNameException: "UTF-8"
    at java.nio.charset.Charset.checkName(Charset.java:315)
    at java.nio.charset.Charset.lookup2(Charset.java:484)
    at java.nio.charset.Charset.lookup(Charset.java:464)
    at java.nio.charset.Charset.defaultCharset(Charset.java:609)
    at sun.nio.cs.StreamEncoder.forOutputStreamWriter(StreamEncoder.java:56)
    at java.io.OutputStreamWriter.<init>(OutputStreamWriter.java:111)
    at java.io.PrintStream.<init>(PrintStream.java:104)
    at java.io.PrintStream.<init>(PrintStream.java:151)
    at java.lang.System.newPrintStream(System.java:1148)
    at java.lang.System.initializeSystemClass(System.java:1192)

0

Ми встановлюємо там два властивості системи разом, і це змушує систему приймати все до utf8

file.encoding=UTF8
client.encoding.overrideUTF-8

7
Властивість client.encoding.override, здається, специфічна для WebSphere.
Крістоф Руссі


0

Нещодавно я наткнувся на систему Notes 6.5 місцевої компанії і дізнався, що веб-пошта відображатиме невстановлювані символи на установці Windows, не локалізованій Чжунвен. Копали кілька тижнів в Інтернеті, з’ясували це всього кілька хвилин тому:

У властивостях Java додайте наступний рядок до параметрів виконання

-Dfile.encoding=MS950 -Duser.language=zh -Duser.country=TW -Dsun.jnu.encoding=MS950

У цьому випадку налаштування UTF-8 не працює.


0

Моя команда зіткнулася з тією ж проблемою на машинах із Windows .. Потім вдалося її вирішити двома способами:

а) Встановити змінну навколишнього середовища (навіть у системних налаштуваннях Windows)

JAVA_TOOL_OPTIONS
-Dfile.encoding = UTF8

b) Введіть наступний фрагмент до свого pom.xml:

 -Dfile.encoding=UTF-8 

ВІД

 <jvmArguments>
 -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8001
 -Dfile.encoding=UTF-8
 </jvmArguments>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.