Die offensichtliche Antwort ist zu verwenden, Charset.defaultCharset()
aber wir haben kürzlich herausgefunden, dass dies möglicherweise nicht die richtige Antwort ist. Mir wurde gesagt, dass sich das Ergebnis von dem tatsächlichen Standardzeichensatz unterscheidet, der von java.io-Klassen bei mehreren Gelegenheiten verwendet wird. Java behält anscheinend zwei Sätze von Standardzeichensätzen bei. Hat jemand irgendwelche Einsichten zu diesem Thema?
Wir konnten einen Fehlerfall reproduzieren. Es ist eine Art Benutzerfehler, aber es kann immer noch die Hauptursache für alle anderen Probleme aufdecken. Hier ist der Code,
public class CharSetTest {
public static void main(String[] args) {
System.out.println("Default Charset=" + Charset.defaultCharset());
System.setProperty("file.encoding", "Latin-1");
System.out.println("file.encoding=" + System.getProperty("file.encoding"));
System.out.println("Default Charset=" + Charset.defaultCharset());
System.out.println("Default Charset in Use=" + getDefaultCharSet());
}
private static String getDefaultCharSet() {
OutputStreamWriter writer = new OutputStreamWriter(new ByteArrayOutputStream());
String enc = writer.getEncoding();
return enc;
}
}
Unser Server benötigt einen Standardzeichensatz in Latin-1, um mit einer gemischten Codierung (ANSI / Latin-1 / UTF-8) in einem Legacy-Protokoll umgehen zu können. Alle unsere Server werden also mit diesem JVM-Parameter ausgeführt.
-Dfile.encoding=ISO-8859-1
Hier ist das Ergebnis auf Java 5,
Default Charset=ISO-8859-1
file.encoding=Latin-1
Default Charset=UTF-8
Default Charset in Use=ISO8859_1
Jemand versucht, die Codierungslaufzeit zu ändern, indem er die Datei.encoding im Code festlegt. Wir alle wissen, dass das nicht funktioniert. Dies löst jedoch anscheinend defaultCharset () aus, hat jedoch keinen Einfluss auf den von OutputStreamWriter verwendeten tatsächlichen Standardzeichensatz.
Ist das ein Fehler oder eine Funktion?
BEARBEITEN: Die akzeptierte Antwort zeigt die Grundursache des Problems. Grundsätzlich können Sie defaultCharset () in Java 5 nicht vertrauen. Dies ist nicht die Standardcodierung, die von E / A-Klassen verwendet wird. Java 6 behebt dieses Problem anscheinend.
quelle
Antworten:
Das ist wirklich seltsam ... Einmal festgelegt, wird der Standardzeichensatz zwischengespeichert und nicht geändert, während sich die Klasse im Speicher befindet. Das Festlegen der
"file.encoding"
Eigenschaft mitSystem.setProperty("file.encoding", "Latin-1");
bewirkt nichts. Bei jedemCharset.defaultCharset()
Aufruf wird der zwischengespeicherte Zeichensatz zurückgegeben.Hier sind meine Ergebnisse:
Ich benutze allerdings JVM 1.6.
(aktualisieren)
OK. Ich habe Ihren Fehler mit JVM 1.5 reproduziert.
Wenn Sie sich den Quellcode 1.5 ansehen, wird der zwischengespeicherte Standardzeichensatz nicht festgelegt. Ich weiß nicht, ob dies ein Fehler ist oder nicht, aber 1.6 ändert diese Implementierung und verwendet den zwischengespeicherten Zeichensatz:
JVM 1.5:
JVM 1.6:
Wenn Sie die Dateicodierung auf
file.encoding=Latin-1
den nächsten AufrufCharset.defaultCharset()
einstellen, geschieht Folgendes: Da der zwischengespeicherte Standardzeichensatz nicht festgelegt ist, wird versucht, den entsprechenden Zeichensatz für den Namen zu findenLatin-1
. Dieser Name wird nicht gefunden, da er falsch ist, und gibt den Standard zurückUTF-8
.Was die Gründe angeht, warum die E / A-Klassen beispielsweise
OutputStreamWriter
ein unerwartetes Ergebnis zurückgeben, unterscheidet sichdie Implementierung von
sun.nio.cs.StreamEncoder
(die von diesen E / A-Klassen verwendet wird) auch für JVM 1.5 und JVM 1.6. Die JVM 1.6-Implementierung basiert auf derCharset.defaultCharset()
Methode zum Abrufen der Standardcodierung, wenn keine für E / A-Klassen bereitgestellt wird. Die JVM 1.5-Implementierung verwendet eine andere MethodeConverters.getDefaultEncodingName();
, um den Standardzeichensatz abzurufen. Diese Methode verwendet einen eigenen Cache des Standardzeichensatzes, der bei der JVM-Initialisierung festgelegt wird:JVM 1.6:
JVM 1.5:
Aber ich stimme den Kommentaren zu. Sie sollten sich nicht auf diese Eigenschaft verlassen . Es ist ein Implementierungsdetail.
quelle
Sieht nach undefiniertem Verhalten aus. Ich weiß, dass Sie in der Praxis die Standardcodierung mithilfe einer Befehlszeileneigenschaft ändern können, aber ich denke nicht, dass definiert ist, was passiert, wenn Sie dies tun.
Fehler-ID: 4153515 bei Problemen beim Festlegen dieser Eigenschaft:
Ich erschrecke, wenn ich sehe, dass Leute die Codierung in der Befehlszeile einstellen - Sie wissen nicht, welchen Code dies beeinflussen wird.
Wenn Sie die Standardcodierung nicht verwenden möchten, legen Sie die gewünschte Codierung explizit über die entsprechende Methode / den entsprechenden Konstruktor fest .
quelle
Erstens ist Latin-1 dasselbe wie ISO-8859-1, daher war die Standardeinstellung für Sie bereits in Ordnung. Richtig?
Sie haben die Codierung mit Ihrem Befehlszeilenparameter erfolgreich auf ISO-8859-1 eingestellt. Sie setzen es auch programmgesteuert auf "Latin-1", aber das ist kein anerkannter Wert einer Dateicodierung für Java. Siehe http://java.sun.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
Wenn Sie dies tun, sieht es so aus, als würde Charset auf UTF-8 zurückgesetzt, wenn Sie sich die Quelle ansehen. Das erklärt zumindest den größten Teil des Verhaltens.
Ich weiß nicht, warum OutputStreamWriter ISO8859_1 anzeigt. Es delegiert an geschlossene sun.misc. * -Klassen. Ich vermute, es geht nicht ganz darum, über denselben Mechanismus zu codieren, was seltsam ist.
Aber natürlich sollten Sie immer angeben, welche Codierung Sie in diesem Code meinen. Ich würde mich nie auf die Plattform-Standardeinstellung verlassen.
quelle
Das Verhalten ist nicht wirklich so seltsam. Ein Blick auf die Implementierung der Klassen wird verursacht durch:
Charset.defaultCharset()
speichert den ermittelten Zeichensatz in Java 5 nicht zwischen.Charset.defaultCharset()
erneute Aufrufen führt zu einer zweiten Auswertung der Systemeigenschaft. Es wurde kein Zeichensatz mit dem Namen "Latin-1" gefunden, daher wirdCharset.defaultCharset()
standardmäßig "UTF-8" verwendet.OutputStreamWriter
speichert jedoch den Standardzeichensatz zwischen und wird wahrscheinlich bereits während der VM-Initialisierung verwendet, sodass der Standardzeichensatz davonCharset.defaultCharset()
abweicht, wenn die Systemeigenschaft "file.encoding" zur Laufzeit geändert wurde.Wie bereits erwähnt, ist nicht dokumentiert, wie sich die VM in einer solchen Situation verhalten muss. In der
Charset.defaultCharset()
API-Dokumentation wird nicht sehr genau festgelegt, wie der Standardzeichensatz ermittelt wird. Es wird lediglich erwähnt, dass dies normalerweise beim Start der VM erfolgt, basierend auf Faktoren wie dem Standardzeichensatz des Betriebssystems oder dem Standardgebietsschema.quelle
Ich habe das vm-Argument im WAS-Server als -Dfile.encoding = UTF-8 festgelegt, um den Standardzeichensatz des Servers zu ändern.
quelle
prüfen
Es scheint dieselbe Codierung zu sein wie die in der Befehlszeile Ihres Systems verwendete.
quelle