La réponse évidente est d'utiliser Charset.defaultCharset()
mais nous avons récemment découvert que ce n'était peut-être pas la bonne réponse. On m'a dit que le résultat est différent du jeu de caractères par défaut réel utilisé par les classes java.io à plusieurs reprises. On dirait que Java conserve 2 ensembles de jeux de caractères par défaut. Quelqu'un a-t-il des idées sur ce problème?
Nous avons pu reproduire un cas d'échec. C'est une sorte d'erreur de l'utilisateur, mais cela peut toujours exposer la cause première de tous les autres problèmes. Voici le 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;
}
}
Notre serveur nécessite un jeu de caractères par défaut en Latin-1 pour gérer un encodage mixte (ANSI / Latin-1 / UTF-8) dans un protocole hérité. Donc tous nos serveurs fonctionnent avec ce paramètre JVM,
-Dfile.encoding=ISO-8859-1
Voici le résultat sur Java 5,
Default Charset=ISO-8859-1
file.encoding=Latin-1
Default Charset=UTF-8
Default Charset in Use=ISO8859_1
Quelqu'un essaie de modifier le runtime d'encodage en définissant le fichier file.encoding dans le code. Nous savons tous que cela ne fonctionne pas. Cependant, cela annule apparemment defaultCharset () mais n'affecte pas le jeu de caractères par défaut réel utilisé par OutputStreamWriter.
Est-ce un bug ou une fonctionnalité?
EDIT: La réponse acceptée montre la cause première du problème. Fondamentalement, vous ne pouvez pas faire confiance à defaultCharset () dans Java 5, qui n'est pas l'encodage par défaut utilisé par les classes d'E / S. Il semble que Java 6 corrige ce problème.
la source
Réponses:
C'est vraiment étrange ... Une fois défini, le jeu de caractères par défaut est mis en cache et il n'est pas modifié tant que la classe est en mémoire. Définir la
"file.encoding"
propriété avecSystem.setProperty("file.encoding", "Latin-1");
ne fait rien. Chaque fois qu'ilCharset.defaultCharset()
est appelé, il renvoie le jeu de caractères mis en cache.Voici mes résultats:
J'utilise JVM 1.6 cependant.
(mettre à jour)
D'accord. J'ai reproduit votre bogue avec JVM 1.5.
En regardant le code source de 1.5, le jeu de caractères par défaut mis en cache n'est pas défini. Je ne sais pas s'il s'agit d'un bogue ou non, mais 1.6 modifie cette implémentation et utilise le jeu de caractères mis en cache:
JVM 1.5:
JVM 1.6:
Lorsque vous définissez le codage du fichier sur
file.encoding=Latin-1
la prochaine fois que vous appelezCharset.defaultCharset()
, ce qui se passe, c'est que le jeu de caractères par défaut mis en cache n'est pas défini, il essaiera de trouver le jeu de caractères approprié pour le nomLatin-1
. Ce nom est introuvable, car il est incorrect et renvoie la valeur par défautUTF-8
.Quant à savoir pourquoi les classes IO telles que
OutputStreamWriter
retournent un résultat inattendu,l'implémentation de
sun.nio.cs.StreamEncoder
(witch est utilisé par ces classes IO) est également différente pour JVM 1.5 et JVM 1.6. L'implémentation de JVM 1.6 est basée sur laCharset.defaultCharset()
méthode permettant d'obtenir le codage par défaut, s'il n'est pas fourni aux classes IO. L'implémentation JVM 1.5 utilise une méthode différenteConverters.getDefaultEncodingName();
pour obtenir le jeu de caractères par défaut. Cette méthode utilise son propre cache du jeu de caractères par défaut qui est défini lors de l'initialisation de la JVM:JVM 1.6:
JVM 1.5:
Mais je suis d'accord avec les commentaires. Vous ne devriez pas vous fier à cette propriété . C'est un détail de mise en œuvre.
la source
Ressemble à un comportement indéfini. Je sais que, dans la pratique, vous pouvez modifier le codage par défaut en utilisant une propriété de ligne de commande, mais je ne pense pas que ce qui se passe lorsque vous faites cela est défini.
ID de bogue: 4153515 sur les problèmes de définition de cette propriété:
Je grince des dents quand je vois des gens définir l'encodage sur la ligne de commande - vous ne savez pas quel code cela va affecter.
Si vous ne souhaitez pas utiliser l'encodage par défaut, définissez explicitement l'encodage souhaité via la méthode / le constructeur approprié .
la source
Premièrement, Latin-1 est identique à ISO-8859-1, donc la valeur par défaut était déjà OK pour vous. Droite?
Vous avez correctement défini le codage sur ISO-8859-1 avec votre paramètre de ligne de commande. Vous le définissez également par programme sur "Latin-1", mais ce n'est pas une valeur reconnue d'un encodage de fichier pour Java. Voir http://java.sun.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
Lorsque vous faites cela, il semble que Charset se réinitialise à UTF-8, en regardant la source. Cela explique au moins la plupart des comportements.
Je ne sais pas pourquoi OutputStreamWriter affiche ISO8859_1. Il délègue aux classes sun.misc. * Source fermée. Je suppose qu'il ne s'agit pas tout à fait de l'encodage via le même mécanisme, ce qui est étrange.
Mais bien sûr, vous devriez toujours spécifier le codage que vous entendez dans ce code. Je ne compterais jamais sur la plate-forme par défaut.
la source
Le comportement n'est pas vraiment si étrange. En regardant dans l'implémentation des classes, cela est causé par:
Charset.defaultCharset()
ne met pas en cache le jeu de caractères déterminé dans Java 5.Charset.defaultCharset()
nouvel appel provoquent une deuxième évaluation de la propriété système, aucun jeu de caractères avec le nom "Latin-1" n'est trouvé, donc la valeur parCharset.defaultCharset()
défaut est "UTF-8".OutputStreamWriter
met cependant en cache le jeu de caractères par défaut et est probablement déjà utilisé lors de l'initialisation de la VM, de sorte que son jeu de caractères par défaut dévieCharset.defaultCharset()
si la propriété système "file.encoding" a été modifiée lors de l'exécution.Comme déjà souligné, il n'est pas documenté comment la VM doit se comporter dans une telle situation. La
Charset.defaultCharset()
documentation de l'API n'est pas très précise sur la façon dont le jeu de caractères par défaut est déterminé, mentionnant seulement qu'il est généralement effectué au démarrage de la VM, en fonction de facteurs tels que le jeu de caractères par défaut du système d'exploitation ou les paramètres régionaux par défaut.la source
J'ai défini l'argument vm dans le serveur WAS comme -Dfile.encoding = UTF-8 pour changer le jeu de caractères par défaut des serveurs.
la source
vérifier
il semble être le même encodage que celui utilisé dans la ligne de commande de votre système.
la source