Comment Trouver le jeu de caractères par Défaut/de Codage en Java?
La réponse évidente est d'utiliser Charset.defaultCharset()
mais nous avons récemment trouvé que ce serait peut-être pas la bonne réponse. On m'a dit que le résultat est différent de réel jeu de caractères par défaut utilisé par java.io classes à plusieurs reprises. Ressemble à Java garde de 2 ensembles de jeu de caractères par défaut. Quelqu'un aurait-il des idées sur ce problème?
Nous avons été en mesure de reproduire un cas d'échec. C'est une sorte d'erreur de l'utilisateur, mais il peut toujours exposer la cause de racine 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 requiert jeu de caractères par défaut dans le Latin-1 pour traiter avec un mélange de codage (ANSI/Latin-1/UTF-8) dans un héritage protocole. Donc, tous nos serveurs fonctionnent avec ce paramètre de 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 changer l'encodage d'exécution en paramètre le fichier.le codage dans le code. Nous savons tous qui ne fonctionne pas. Cependant, ce qui, apparemment, jette hors defaultCharset() mais cela n'affecte pas le vrai jeu de caractères par défaut utilisé par OutputStreamWriter.
Est-ce un bug ou fonctionnalité?
EDIT: La accepté de répondre montre la cause racine du problème. Fondamentalement, vous ne pouvez pas faire confiance defaultCharset() en Java 5, ce qui n'est pas l'encodage utilisé par défaut par les e/S des classes. Ressemble à Java 6 corrige ce problème.
- C'est bizarre, depuis le defaultCharset utilise une variable statique qui est définie une seule fois (accoring à la docs - à VM de démarrage). Ce VM Vendeur utilisez-vous?
- J'ai été en mesure de reproduire ce sur Java 5, à la fois sur le Soleil/Linux et Apple/mac OS X.
- Ce qui explique pourquoi defaultCharset() ne pas mettre en cache le résultat. J'ai encore besoin de savoir ce qu'est le vrai jeu de caractères par défaut utilisé par IO classes. Il doit y avoir un autre jeu de caractères par défaut de cache quelque part d'autre.
- Codeur, je suis encore en recherche sur le sujet. La seule chose que je sais, c'est que le jeu de caractères.defaulyCharset() n'est pas appelé de soleil.nio.cs.StreamEncoder dans la JVM 1.5. Dans la JVM 1.6 le jeu de caractères.defaulyCharset() la méthode est appelée donner les résultats escomptés. JVM 1.5 mise en œuvre de StreamEncoder est mise en cache de la précédente encodage, en quelque sorte.
Vous devez vous connecter pour publier un commentaire.
C'est vraiment étrange... une Fois réglé, le jeu de caractères par défaut est mis en cache et il n'est pas changé, alors que la classe est en mémoire. Réglage de la
"file.encoding"
propriété avecSystem.setProperty("file.encoding", "Latin-1");
ne fait rien. Chaque foisCharset.defaultCharset()
est appelée, elle retourne la mise en cache jeu de caractères.Voici mes résultats:
Je suis en utilisant JVM 1.6 si.
(mise à jour)
Ok. Je l'ai fait reproduire votre bug avec la JVM 1.5.
Regardant le code source de la version 1.5, la mise en cache jeu de caractères par défaut n'est pas définie. Je ne sais pas si c'est un bug ou pas mais de 1,6 changements de cette mise en œuvre et utilise la mise en cache charset:
JVM 1.5:
JVM 1.6:
Lorsque vous définissez l'encodage du fichier à
file.encoding=Latin-1
la prochaine fois que vous appelezCharset.defaultCharset()
, ce qui se passe, parce que la mise en cache jeu de caractères par défaut n'est pas défini, il va essayer de trouver le bon jeu de caractères pour le nomLatin-1
. Ce nom n'est pas trouvé, parce que c'est incorrect, et retourne la valeur par défautUTF-8
.Quant à savoir pourquoi le IO classes telles que
OutputStreamWriter
renvoyer un résultat inattendu,la mise en œuvre de
sun.nio.cs.StreamEncoder
(sorcière est utilisé par ces IO classes) est différente ainsi que pour la JVM JVM 1.5 et 1.6. La JVM 1.6 mise en œuvre est basée dans leCharset.defaultCharset()
méthode pour obtenir le codage par défaut, si l'on n'est pas fourni IO classes. La JVM 1.5 mise en œuvre 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 est définie sur la JVM de l'initialisation:JVM 1.6:
JVM 1.5:
Mais je suis d'accord avec les commentaires. Vous ne devriez pas compter sur cette propriété. C'est un détail d'implémentation.
Ressemble à un comportement indéterminé. Je sais que, dans la pratique, vous pouvez modifier l'encodage par défaut à l'aide d'une propriété de ligne de commande, mais je ne pense pas que ce qui se passe quand vous faites ceci est défini.
Bug ID: 4153515 sur les problèmes de la définition de cette propriété:
Je grince des dents quand je vois des gens réglage de l'encodage sur la ligne de commande - vous ne savez pas quel est le code qui va affecter.
Si vous ne souhaitez pas utiliser le codage par défaut, définir l'encodage vous ne voulez explicitement via la méthode appropriée/constructeur.
D'abord, Latin-1 est la même que la norme ISO-8859-1, donc, le défaut était déjà OK pour vous. Droit?
Vous avez réussi à définir l'encodage ISO-8859-1 avec votre paramètre de ligne de commande. Vous avez aussi la définir par programme pour "Latin-1", mais ce n'est pas une valeur reconnue de l'encodage d'un fichier Java. Voir http://java.sun.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
Lorsque vous faites cela, ressemble à un jeu de caractères remet à UTF-8, en regardant la source. Qu'au moins explique la plus grande partie du comportement.
Je ne sais pas pourquoi OutputStreamWriter montre ISO8859_1. Il délègue à code source fermé soleil.misc.* des classes. Je devine que ce n'est pas tout à fait affaire avec l'encodage via le même mécanisme, ce qui est étrange.
Mais de sûr, vous devriez toujours être en spécifiant l'encodage que tu veux dire dans ce code. Je n'avais jamais compter sur la plate-forme par défaut.
Le comportement n'est pas vraiment étrange. La recherche dans la mise en œuvre des classes, il est causé par:
Charset.defaultCharset()
n'est pas mise en cache de déterminer le jeu de caractères en Java 5.Charset.defaultCharset()
nouveau provoque une deuxième évaluation du système de propriété, pas de jeu de caractères avec le nom "Latin-1" est trouvé, doncCharset.defaultCharset()
par défaut "UTF-8".OutputStreamWriter
est cependant la mise en cache du jeu de caractères par défaut et est probablement déjà utilisé au cours de VM d'initialisation, de sorte que son jeu de caractères par défaut qui détourne deCharset.defaultCharset()
si la propriété de système de fichiers".l'encodage" a été modifiée lors de l'exécution.Comme l'a déjà souligné, il n'est pas documenté la façon dont la machine virtuelle doit se comporter dans une telle situation. Le
Charset.defaultCharset()
documentation de l'API n'est pas très précis sur la façon dont le jeu de caractères par défaut est déterminé, le seul fait de mentionner qu'il se fait habituellement sur les VM de démarrage, en fonction de facteurs comme l'OS jeu de caractères par défaut ou des paramètres régionaux par défaut.J'ai mis la machine virtuelle argument a ÉTÉ server en tant que-Dfile.encoding=UTF-8 pour modifier les serveurs de jeu de caractères par défaut.
vérifier
il semble être le même encodage que celui utilisé dans votre système en ligne de commande.