Varsayılan Java karakter kodlamasını ayarlama


362

JVM (1.5.x) tarafından kullanılan varsayılan karakter kodlamasını program aracılığıyla nasıl düzgün bir şekilde ayarlayabilirim?

-Dfile.encoding=whateverEskiden eski JVM'ler için bir yol olduğunu okudum . İçeri girmeyeceğim nedenlerden dolayı o lüksüm yok.

Denedim:

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

Ve özellik ayarlanır, ancak getBytesaşağıdaki son çağrının UTF8'i kullanmasına neden görünmüyor :

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());

Mükemmel yorumlar çocuklar - ve kendimi zaten düşündüğüm şeyler. Ne yazık ki ben üzerinde hiçbir kontrol var bir temel String.getBytes () çağrısı var. Şu anda dolaşmak için gördüğüm tek yol, varsayılan kodlamayı programlı olarak ayarlamaktır. Başka öneriniz var mı?

6
ilgisiz olabilir ancak UTF8 "UTF8", "UTF-8" veya "utf8" ile ayarlandığında fark vardır. Son zamanlarda, IBM WAS 6.1 EJB ve WEB kaplarının kodlamayı tanımlamak için kullanılan (büyük / küçük harf duyarlılığı açısından) dizeleri farklı şekilde ele aldığını buldum.
igor.beslic

5
Sadece bir detay ama: UTF-8'i UTF8'e tercih edin (sadece eski standarttır). Bu hala 2012'de geçerlidir ...
Christophe Roussy

4
Ayarlama veya okuma file.encodingözelliği olan desteklenmez .
McDowell

@ erickson Karakter tabanlı G / Ç akışları ( class Reader& 'nin tüm alt sınıfları class Writer) kullanıldığında, "file.encoding" in ilgili olduğu doğru değil mi? Çünkü class FileInputStreambayt I / O akışı dayanır, böylece bir byte temelli I / O akışında karakter kümesine önemsemeliyiz neden?
Aralık'ta aşırı döviz değişimi

Yanıtlar:


311

Ne yazık ki, file.encodingJVM başlarken özellik belirtilmelidir; ana yöntem girilen süre ile, karakter tarafından kullanılan kodlayan String.getBytes()ve varsayılan kurucular InputStreamReaderve OutputStreamWriterkalıcı önbelleğe edilmiştir.

As Edward Grech işaret, böyle bir özel durumda, ortam değişkeni JAVA_TOOL_OPTIONS olabilir bu özelliği belirtmek için kullanılabilir, ancak normalde böyle bitti:

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

Charset.defaultCharset()file.encodingözelliğindeki değişiklikleri yansıtır , ancak çekirdek Java kitaplıklarındaki varsayılan karakter kodlamasını belirlemesi gereken kodun çoğu bu mekanizmayı kullanmaz.

Kodlama veya kod çözme işlemi sırasında, file.encodingözelliği sorgulayabilir veya Charset.defaultCharset()geçerli varsayılan kodlamayı bulabilir ve belirtmek için uygun yöntemi veya yapıcı aşırı yüklemesini kullanabilirsiniz.


9
Tamlık için, biraz hile ile gerçekten kullanılan varsayılan kodlamaya (önbelleğe alındığı gibi) ulaşabileceğinizi eklemek istiyorum, Gary Cronin sayesinde: byte [] byteArray = {'a'}; InputStream inputStream = yeni ByteArrayInputStream (byteArray); InputStreamReader okuyucu = yeni InputStreamReader (inputStream); String defaultEncoding = reader.getEncoding (); lists.xcf.berkeley.edu/lists/advanced-java/1999-Ekim / Ekim
Stijn de Witt

2
JDK-4163515 , file.encodingJVM başladıktan sonra sysprop'u ayarlama hakkında daha fazla bilgi içeriyor.
Caspar

2
Başımı kaşıyordum çünkü bu komut Windows, linux ve mac üzerinde mükemmel çalışmıyor ... sonra "böyle bir değerin etrafına koydum: java -D" file.encoding = UTF-8 "-jar
cabaji99

Java Bahar Önyükleme durumunda cevabımı kontrol et: stackoverflow.com/a/48952844/986160
Michail Michailidis

170

Gönderen JVM ™ Aracı Arayüz belgelerinde ...

Komut satırına her zaman erişilemediğinden veya değiştirilemediğinden, örneğin katıştırılmış VM'lerde veya yalnızca komut dosyalarının derinliklerinde JAVA_TOOL_OPTIONSbaşlatılan VM'lerde, bu durumlarda aracıların başlatılması için bir değişken sağlanır.

(Windows) ortam değişkeni ayarlayarak JAVA_TOOL_OPTIONSiçin -Dfile.encoding=UTF8, (Java) Systemözelliği otomatik olarak JVM her başlatıldığında ayarlanacaktır. Aşağıdaki mesaj gönderileceği için parametrenin alındığını bileceksiniz System.err:

Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8


Tomcat günlüklerinde "Alındı ​​..." ifadesinin basılacağını biliyor musunuz?
thatidiotguy

1
Merhaba Edward Grech Çözümünüz için teşekkür ederim. Probmem başka bir forum gönderisinde çözüldü. stackoverflow.com/questions/14814230/…
Smaug

8
UTF8veya UTF-8?
Küçük

1
@Tiny Java her ikisini de anlar. stackoverflow.com/questions/6031877/…
DLight

Çözümünüz benim zamanımı kurtardı, çok teşekkürler !!
Sobhan

67

Kesinlikle işe yarayan bir hacky yolu var!

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

Bu şekilde, karakter setinin ayarlanmadığını düşünecek JVM'yi kandıracak ve onu çalışma zamanında tekrar UTF-8'e ayarlayacaksınız!


2
Benim için NoSuchFieldException
SparK

10
Saldırının çalışması için güvenlik yöneticisinin kapalı olduğunu varsaymanız gerekir. Bir JVM bayrağı ayarlamanın bir yolu yoksa, (muhtemelen) güvenlik yöneticisi etkin bir sisteminiz de olabilir.
Yonatan

3
JDK9 yok değil artık bu kesmek onaylıyor. 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: Bu iyi bir cevap değil, kirli bir saldırı ve gerçekleşmeyi bekleyen bir sorun. Bu sadece acil durum önlemi olarak kullanılmalıdır.
sleske

1
@Enerccio: Java'nın bunu ayarlamanın bir yolu olup olmadığı tartışılabilir - ayrıca, geliştiricilerin alakalı olduğunda kodlamayı "açıkça" belirtmeleri gerektiği de iddia edilebilir. Her halükarda, bu çözüm daha uzun vadede ciddi sorunlara neden olma potansiyeline sahiptir, bu nedenle "sadece acil kullanım için" uyarı. Aslında, acil durum kullanımı bile tartışmalıdır, çünkü bunu yapmanın desteklenen bir yolu vardır , başka bir cevapta açıklandığı gibi JAVA_TOOL_OPTIONS.
sleske

38

Platformun varsayılan karakter kümesini ayarlamaktan daha iyi bir yaklaşım olduğunu düşünüyorum, özellikle de uygulama dağıtımını etkileme konusunda kısıtlamalarınız var gibi görünse de, platformu daha güvenli olarak adlandırmaktır String.getBytes("charsetName"). Bu şekilde uygulamanız, kontrolü dışındaki şeylere bağımlı olmaz.

Şahsen String.getBytes(), geliştiricinin muhtemelen değişen varsayılan karakter kümesini hesaba katmadığı, gördüğüm birkaç durumda ciddi sorunlara neden olduğu için, kullanımdan kaldırılması gerektiğini hissediyorum .


18

Orijinal sorunuza cevap veremiyorum ama size bazı önerilerde bulunmak istiyorum - JVM'nin varsayılan kodlamasına bağlı kalmayın. Kodunuzda istenen kodlamayı (yani "UTF-8") açıkça belirtmek her zaman en iyisidir. Bu şekilde, farklı sistemler ve JVM konfigürasyonlarında bile çalışacağını biliyorsunuz.


7
Tabii ki, bir masaüstü uygulaması yazıyor ve herhangi bir kodlama meta verisi olmayan bazı kullanıcı tanımlı metinleri işliyorsanız - platform varsayılan kodlaması, kullanıcının ne kullanabileceği konusunda en iyi tahmininizdir.
Michael Borgwardt

@MichaelBorgwardt "o zaman platform varsayılan kodlaması en iyi tahmindir" varsayılanı değiştirmek istemenin o kadar iyi bir fikir olmadığını tavsiye ediyor gibi görünüyorsunuz . Yani, mümkün olan her yerde, başka bir şey mümkün olmadığında verilen veriyi kullanarak açık bir kodlama mı kullanıyorsunuz?
Raedwald

1
@Raedwald: evet, demek istediğim buydu. Platformun varsayılan kodlaması, (en azından bir son kullanıcı makinesinde), sistemin yerel olarak kullanacağı yerel ayarda kullanıcıların kullandığı alandır. Daha iyi (yani belgeye özgü) bilginiz yoksa kullanmanız gereken bilgilerdir.
Michael Borgwardt

1
@MichaelBorgwardt Saçmalık. Giriş kodlamasını otomatik olarak algılamak için bir kitaplık kullanın ve BOM ile Unicode olarak kaydedin. Kodlama cehennemi ile başa çıkmanın ve savaşmanın tek yolu budur.
Aleksandr Dubinsky

Bence siz ikiniz aynı sayfada değilsiniz. Raedwald kod çözme işleminden sonra işleme hakkında konuşurken Michael kod çözme hakkında konuşuyor.
WesternGun

12

Bunu dene :

    new OutputStreamWriter( new FileOutputStream("Your_file_fullpath" ),Charset.forName("UTF8"))

5

Aynı sorunları yaşıyorduk. Metodik olarak bu makaleden (ve diğerlerinden) birkaç öneri denemedik. Ayrıca ekleme denedik -Dfile.encoding=UTF8ve hiçbir şey çalışıyor gibi görünüyordu.

Yerel ayarı kırabilir nasıl bu sorunu yaşıyorsanız insanlar için aşağıdaki makale nihayet bize izini yardımcı açıklanır unicode/UTF-8içindeJava/Tomcat

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

Yerel ayarın ~/.bashrcdosyada doğru ayarlanması bizim için çalıştı.


4

Bir çok şey denedim, ama burada örnek kod mükemmel çalışıyor. bağlantı

Kodun temel noktası:

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

4

Spring Boot kullanıyorsanız ve bağımsız değişkeni file.encodingJVM'de geçirmek istiyorsanız, bunu şu şekilde çalıştırmanız gerekir:

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

JTwigşablonlar kullandığımız ve işletim sisteminin ANSI_X3.4-1968öğrendiğimizSystem.out.println(System.getProperty("file.encoding"));

Umarım bu birine yardımcı olur!


2

Amazon (AWS) Elastik Beanstalk kullanıyorum ve başarıyla UTF-8 olarak değiştirdim.

Elastik Beanstalk'ta Yapılandırma> Yazılım, "Ortam özellikleri" bölümüne gidin. (Değer) -Dfile.encoding = UTF8 ile JAVA_TOOL_OPTIONS ekleyin

Kaydettikten sonra, ortam UTF-8 kodlamasıyla yeniden başlayacaktır.


1

Ne yaptığınız konusunda net değil ve bu noktada kontrolünüz yok. Hedef dosyada farklı bir OutputStream sınıfı arayabilirseniz, varsayılan olarak UTF-8 diyelim ki, dizeleri baytlara dönüştürdüğünüz bir karakter seti altında dönüştüren bir OutputStream alt türü kullanabilirsiniz. Modifiye edilmiş UTF-8 ihtiyaçlarınız için yeterliyse, şunları kullanabilirsiniz 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

Bu yaklaşım uygun değilse, burada veri akışı ve yürütme ortamı açısından neleri kontrol edebileceğinizi ve neyi kontrol edemeyeceğinizi açıklığa kavuşturmak size yardımcı olabilir (ancak bunun bazen belirtilenden daha kolay olduğunu biliyorum). İyi şanslar.


5
DataInputStream ve DataOutputStream, asla düz metin dosyalarıyla kullanılmaması gereken özel amaçlı sınıflardır. Kullandıkları değiştirilmiş UTF-8, gerçek UTF-8 ile uyumlu değildir. Ayrıca, OP çözümünüzü kullanabilseydi, bu iş için doğru aracı da kullanabilirdi: OutputStreamWriter.
Alan Moore

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

jenkins görevi yapılandırılırken aşağıdaki hatayı gidermek için exec-maven-plugin ile birlikte çalıştı.

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

Orada iki sistem özelliğini bir araya getirdik ve sistemin her şeyi utf8'e almasını sağlıyor

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

7
Client.encoding.override özelliği WebSphere'e özgü görünüyor.
Christophe Roussy


0

Son zamanlarda yerel bir şirketin Notes 6.5 sistemine çarptım ve web postasının Zhongwen olmayan yerelleştirilmiş bir Windows kurulumunda tanımlanamayan karakterler göstereceğini öğrendim. Birkaç hafta çevrimiçi kazdık, sadece birkaç dakika önce anladım:

Java özelliklerinde, Çalışma Zamanı Parametrelerine aşağıdaki dizeyi ekleyin

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

Bu durumda UTF-8 ayarı çalışmaz.


0

Ekibim Windows ile makinelerde aynı sorunla karşılaştı .. daha sonra iki şekilde çözmeyi başardı:

a) Çevre değişkenini ayarlayın (Windows sistem tercihlerinde bile)

JAVA_TOOL_OPTIONS
-Dfile.encoding = UTF8

b) Aşağıdaki snippet'i pom.xml'nize ekleyin:

 -Dfile.encoding=UTF-8 

İÇİNDE

 <jvmArguments>
 -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8001
 -Dfile.encoding=UTF-8
 </jvmArguments>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.