web-dev-qa-db-fra.com

Pourquoi String.getBytes () de Java utilise "ISO-8859-1"

de Java.lang.StringCoding:

String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;

C'est ce qui est utilisé à partir de Java.lang.getBytes (), dans linux jdk 7, j'ai toujours eu l'impression que UTF-8 est le jeu de caractères par défaut?

Merci

18
Amnon

C'est un peu compliqué ...

Java essaie d'utiliser le codage de caractères par défaut pour renvoyer des octets à l'aide de String.getBytes ().

  • Le jeu de caractères par défaut est fourni par la propriété système file.encoding.
  • Ceci est mis en cache et il est inutile de le modifier via System.setProperty (..) après le démarrage de la JVM.
  • Si la propriété file.encoding ne correspond pas à un jeu de caractères connu, l'UTF-8 est spécifié.

.... Voici la partie délicate (qui n'entrera probablement jamais en jeu) ....

Si le système ne peut pas décoder ou encoder des chaînes en utilisant le jeu de caractères par défaut (UTF-8 ou autre), il y aura alors un retour à ISO-8859-1. Si la solution de secours ne fonctionne pas ... le système échouera!

.... Vraiment ... (halètement!) ... Pourrait-il planter si mon jeu de caractères spécifié ne peut pas être utilisé, et UTF-8 ou ISO-8859-1 sont également inutilisables?

Oui. L'état des commentaires source Java source dans la méthode StringCoding.encode (...):

// Si nous ne pouvons pas trouver ISO-8859-1 (un encodage requis), alors les choses vont sérieusement mal avec l'installation.

... puis il appelle System.exit (1)


Alors, pourquoi y a-t-il un repli intentionnel sur ISO-8859-1 dans la méthode getBytes ()?

Il est possible, bien que peu probable, que les utilisateurs JVM ne prennent pas en charge le décodage et l'encodage en UTF-8 ou le jeu de caractères spécifié au démarrage de la JVM.

Ensuite, le jeu de caractères par défaut est-il utilisé correctement dans la classe String pendant getBytes ()?

Non. Mais la meilleure question est ...


String.getBytes () livre-t-il ce qu'il promet?

Le contrat tel que défini dans le Javadoc est correct.

Le comportement de cette méthode lorsque cette chaîne ne peut pas être codée dans le jeu de caractères par défaut n'est pas spécifié. La classe CharsetEncoder doit être utilisée lorsque plus de contrôle sur le processus d'encodage est requis.


La bonne nouvelle (et une meilleure façon de faire les choses)

Il est toujours conseillé de spécifier explicitement "ISO-8859-1" ou "US-ASCII" ou "UTF-8" ou tout autre jeu de caractères que vous souhaitez lors de la conversion d'octets en chaînes de vice-versa - sauf si - vous avez déjà obtenu le jeu de caractères par défaut et 100% sûr que c'est celui dont vous avez besoin.

Utilisez plutôt cette méthode:

public byte[] getBytes(String charsetName)

Pour trouver la valeur par défaut pour votre système, utilisez simplement:

Charset.defaultCharset()

J'espère que cela pourra aider.

36
The Coordinator

La méthode String.getBytes() sans paramètre ne pas utilise ISO-8859-1 par défaut. Il utilisera le codage de plate-forme par défaut, si cela peut être déterminé. Si, cependant, c'est manquant ou est un encodage non reconnu, il revient à ISO-8859-1 comme "défaut par défaut".

Vous devriez très rarement voir cela dans la pratique. Normalement, l'encodage par défaut de la plateforme sera détecté correctement.

Cependant, je vous suggère fortement de spécifier un codage de caractères explicite à chaque fois que vous effectuez une opération de codage ou de décodage. Même si vous voulez la plate-forme par défaut, spécifiez-la explicitement.

12
Jon Skeet

C'est pour des raisons de compatibilité.

Historiquement, toutes les méthodes Java sous Windows et Unix ne spécifiant pas de jeu de caractères utilisaient la méthode courante à l'époque, c'est-à-dire "ISO-8859-1").

Comme mentionné par Isaac et le javadoc, le codage de plate-forme par défaut est utilisé (voir Charset.Java ):

594    public static Charset defaultCharset() {
595        if (defaultCharset == null) {
596            synchronized (Charset.class) {
597                String csn = AccessController.doPrivileged(
598                    new GetPropertyAction("file.encoding"));
599                Charset cs = lookup(csn);
600                if (cs != null)
601                    defaultCharset = cs;
602                else
603                    defaultCharset = forName("UTF-8");
604            }
605        }
606        return defaultCharset;
607    }

Spécifiez toujours le jeu de caractères lors de la conversion de chaîne en octets ou d'octets en chaîne.

Même lorsque, comme c'est le cas pour String.getBytes(), vous trouvez toujours une méthode non obsolète ne prenant pas le jeu de caractères (la plupart d'entre elles étaient obsolètes lorsque Java 1.1 est apparu). Tout comme avec endianness, le format de la plate-forme n'a pas d'importance, ce qui est pertinent, c'est la norme du format de stockage.

5
Denys Séguret

Élaborez sur la réponse de Skeet (qui est bien sûr la bonne)

Dans Java.lang.String source getBytes() appelle StringCoding.encode(char[] ca, int off, int len) qui a sur sa première ligne:

String csn = Charset.defaultCharset().name();

Ensuite (pas immédiatement mais absolument), il appelle static byte[] StringEncoder.encode(String charsetName, char[] ca, int off, int len) d'où vient la ligne que vous avez citée - en passant le nom du jeu de caractères le csn - donc dans cette ligne le charsetName sera le jeu de caractères par défaut s'il en existe un.

1
Mr_and_Mrs_D