1. Processus de conversion de codage Java
Nous utilisons toujours un fichier de classe Java pour interagir avec les utilisateurs le plus directement (entrée, sortie), et le texte contenu dans ces contenus interactifs peut contenir le chinois. Que ces classes Java interagissent avec la base de données ou avec la page frontale, leur cycle de vie est toujours comme ceci:
(1) Les programmeurs écrivent du code du programme via un éditeur sur le système d'exploitation et enregistrent le système d'exploitation sous le format de .java. Nous appelons ces fichiers les fichiers source.
(2) Compilez ces fichiers source via Javac.exe dans JDK pour former la classe .class.
(3) Exécutez ces classes directement ou déployez-les dans un conteneur Web pour obtenir le résultat de sortie.
Ces processus sont observés du point de vue macro, et il n'est certainement pas possible de comprendre cela. Nous devons vraiment comprendre comment Java est encodé et décodé:
Étape 1: Lorsque nous utilisons un éditeur pour écrire un fichier source Java, le fichier de programme utilisera le format d'encodage par défaut du système d'exploitation (généralement notre système d'exploitation chinois utilise le format d'encodage GBK) pour former un fichier .java. Le fichier source Java est enregistré dans le format de codage de fichiers. Le code suivant peut afficher la valeur du paramètre File.encoding du système.
System.out.println (System.getProperty ("file.encoding")); Étape 2: Lorsque nous utilisons Javac.exe pour compiler notre fichier Java, JDK confirmera d'abord son codage de paramètre de compilation pour déterminer le jeu de caractères de code source. Si nous ne spécifions pas le paramètre de compilation, JDK obtiendra d'abord le paramètre File.Encoding par défaut du système d'exploitation, puis JDK convertira le programme source Java que nous avons écrit à partir du format d'encodage File.encoding au format Unicode par défaut à l'intérieur de Java et le mettant en mémoire.
Étape 3: JDK écrit les informations compilées et enregistrées sur la mémoire ci-dessus dans le fichier de classe pour former un fichier .class. À l'heure actuelle, le fichier .class est encodé Unicode, ce qui signifie que le contenu de nos fichiers .class communs est converti en format de codage Unicode, qu'il s'agisse de caractères chinois ou anglais.
Dans cette étape, la méthode de traitement des fichiers source JSP est un peu différente: le conteneur Web appelle le compilateur JSP. Le compilateur JSP vérifiera d'abord si le fichier JSP a le format d'encodage de fichier. S'il n'est pas défini, le compilateur JSP appellera le JDK pour convertir le fichier JSP en une classe de servlet temporaire à l'aide de la méthode de codage par défaut, puis le compiler en fichier .class et le garder dans un dossier temporaire.
Étape 4: Exécutez la classe compilée: il y aura plusieurs situations ici
(1) Exécutez directement sur la console.
(2) Classe JSP / Servlet.
(3) entre la classe Java et la base de données.
Chacune de ces trois situations aura différentes façons de le faire.
1. Cours fonctionnant sur la console
Dans ce cas, le JVM lira d'abord le fichier de classe enregistré dans le système d'exploitation en mémoire. À l'heure actuelle, le fichier de classe en mémoire est codé dans Unicode, puis le JVM l'exécutera. Si l'utilisateur doit saisir des informations, les informations d'entrée par l'utilisateur seront codées au format de fichier. Une fois le programme exécuté, le résultat est converti en format de fichier. Encodage et retourné au système d'exploitation et sortie en interface. L'ensemble du processus est le suivant:
Dans l'ensemble du processus ci-dessus, aucune erreur ne peut se produire dans toute conversion de codage impliquée, sinon un code brouillé ne se produira.
2.Servlet Classe
Étant donné que les fichiers JSP seront finalement convertis en fichiers de servlet (mais l'emplacement de stockage est différent), nous inclurons également les fichiers JSP ici.
Lorsqu'un utilisateur demande un servlet, le conteneur Web appelle son JVM pour exécuter le servlet. Tout d'abord, le JVM chargera la classe de servlet en mémoire. Le code servlet en mémoire est dans le format de codage Unicode. Ensuite, le JVM exécute le servlet en mémoire. Pendant l'exécution, si vous avez besoin d'accepter les données transmises du client (telles que les données transmises par formulaires et URL), le conteneur Web acceptera les données entrantes. Au cours du processus de réception, si le programme définit le codage des paramètres entrants, le format d'encodage de jeu est adopté. S'il n'est pas défini, le format de codage ISO-8859-1 par défaut est adopté. Après les données reçues, le JVM convertira le format de codage en Unicode et le stockera en mémoire. Après avoir exécuté le servlet, les résultats de sortie sont générés et le format de codage de ces résultats de sortie est toujours Unicode. Immédiatement après, le conteneur Web enverra directement la chaîne de format de codage Unicode générée au client. Si le programme spécifie le format de codage au moment de la sortie, il sera sorti du navigateur en fonction du format de codage spécifié. Sinon, le format de codage ISO-8859-1 par défaut est adopté. L'ensemble du flux de processus est le suivant:
3. Pièce de base de données
Nous savons que la connexion entre les programmes Java et les bases de données est connectée via le pilote JDBC, et le pilote JDBC est par défaut au format de codage ISO-8859-1. C'est-à-dire que lorsque nous transmettons des données à la base de données via le programme Java, JDBC convertira d'abord les données du format de codage Unicode en format de codage ISO-8859-1, puis les stocker dans la base de données, c'est-à-dire lorsque la base de données enregistre les données, le format par défaut est ISO-8859-1.
2. Encodage et décodage
Ce qui suit mettra fin aux opérations de codage et de décodage que Java doit effectuer dans ces occasions, et trier le processus intermédiaire en détail pour maîtriser davantage le processus de codage et de décodage de Java. Il y a quatre scénarios principaux en Java qui nécessitent un codage et un décodage:
(1): opération d'E / S
(2): mémoire
(3): base de données
(4): Javaweb
Ce qui suit introduit principalement les deux scénarios précédents. Tant que la pièce de la base de données est définie correctement, il n'y aura aucun problème. Il y a trop de scénarios Javaweb et vous devez comprendre le codage du décodage URL, Get, Post et Servlet, donc l'introduction LZ du scénario Javaweb.
1.i / o opération
Dans le précédent, LZ a mentionné que le problème brouillé n'est rien de plus que l'incohérence du format de codage pendant le processus de transcodage. Par exemple, UTF-8 est utilisé pour le codage et GBK est utilisé pour le décodage. Cependant, la raison la plus fondamentale est qu'il y a un problème avec la conversion du caractère à octet ou de l'octet à caractéristique, et le principal scénario de conversion dans ce cas est l'opération d'E / S. Bien sûr, les opérations d'E / S incluent principalement des E / S de réseau (c'est-à-dire Javaweb) et des E / S de disque. Les E / S de réseau sont introduites dans la section suivante.
Tout d'abord, regardons l'opération d'encodage d'E / S.
InputStream est la superclasse de toutes les classes du flux d'entrée d'octets, et le lecteur est la classe abstraite du lecteur. Java lit les fichiers d'une manière divisée en flux d'octets et par flux de caractères. InputStream et Reader sont les superclasses de ces deux méthodes de lecture.
Par octet, nous utilisons généralement la méthode inputStream.read () pour lire les octets dans le flux de données (read () ne lit qu'un octet à la fois, ce qui est très lent. Nous utilisons généralement la lecture (octet [])), puis l'enregistrer dans un tableau d'octet [], et enfin la convertir en chaîne. Lorsque nous lisons un fichier, le codage des octets dépend du format de codage utilisé par le fichier, et le problème d'encodage sera également impliqué dans la conversion en processus de chaîne. Si les formats d'encodage sont différents entre les deux, le problème peut se produire. Par exemple, il y a un problème que le format de codage Test.txt est UTF-8, donc le format de codage de flux de données obtenu lors de la lecture d'un fichier via un flux d'octets est UTF-8. Si nous ne spécifions pas le format de codage pendant la conversion en chaîne, nous utilisons le format de codage du système (GBK) par défaut au décodage. Étant donné que les formats de codage des deux sont incohérents, le code brouillé se produira certainement dans le processus de construction de la chaîne, comme suit:
File file = new File ("c: //test.txt"); InputStream input = new FileInputStream (fichier); StringBuffer Buffer = new StringBuffer (); octet [] octets = nouveau octet [1024]; for (int n; (n = input.read (bytes))! = - 1;) {buffer.append (new String (bytes, 0, n)); } System.out.println (tampon); Le résultat de sortie est brouillé ...
Le contenu dans test.txt est: je suis CM.
Pour éviter le code brouillé, spécifiez le format de codage pendant le processus de construction de la chaîne afin que les formats de codage des deux soient codants pendant le codage et le décodage:
Buffer.APPEND (nouvelle chaîne (octets, 0, n, "utf-8"));
Par personnage, le flux de personnage peut être considéré comme un flux de wrapper. Sa couche sous-jacente utilise toujours un flux d'octets pour lire les octets, puis il décode les octets de lecture en caractères en utilisant la méthode de codage spécifiée. Dans Java, Reader est une superclasse qui lit les flux de personnages. Donc, du point de vue inférieur, il n'y a pas de différence entre la lecture des fichiers par octets et la lecture par caractère. Lors de la lecture, la lecture du personnage est laissée avec des octets à chaque fois et les flux d'octets lisent un octet à la fois.
Les octets et la conversion de caractères convertissent les octets en caractères sont essentiellement InputStreamReader. L'API est expliquée comme suit: InputStreamReader est le pont entre le flux d'octets vers le flux de caractères: il lit des octets en utilisant le charset spécifié et les décoche en caractères. Le jeu de caractères qu'il utilise peut être spécifié ou explicitement donné par le nom, ou il peut accepter le jeu de caractères par défaut de la plate-forme. Chaque appel à une méthode read () dans leader InputStreamRed entraîne un ou plusieurs octets lus à partir du flux d'entrée sous-jacent. Pour permettre une conversion efficace de l'octet au caractère, vous pouvez lire plus d'octets à partir du flux sous-jacent à l'avance, dépassant les octets nécessaires pour satisfaire l'opération de lecture actuelle. L'explication de l'API est très claire. InputStreamReader utilise toujours la lecture des octets lors de la lecture du fichier en bas. Après avoir lu les octets, il doit analyser les caractères en fonction d'un format de codage spécifié. S'il n'y a pas de format de codage spécifié, il adopte le format de codage par défaut du système.
String file = "c: //test.txt"; String charSet = "UTF-8"; // Écrivez des caractères à convertir en stream byte fileOutputStream outputStream = new FileOutputStream (file); OutputStreamWriter writer = new OutputStreamWriter (OutputStream, Charset); essayez {writer.write ("je suis cm"); } enfin {writer.close (); } // Lisez les octets pour convertir en caractères FileInputStream inputStream = new FileInputStream (fichier); InputStreamReader Reader = new InputStreamReader (InputStream, Charset); StringBuffer Buffer = new StringBuffer (); char [] buf = nouveau char [64]; int count = 0; try {while ((count = reader.read (buf))! = -1) {buffer.append (buf, 0, count); }} enfin {reader.close (); } System.out.println (tampon); 2. Mémoire
Tout d'abord, regardons le code simple suivant
String s = "je suis cm"; octet [] octets = s.getBytes (); String S1 = new String (Bytes, "GBK"); String s2 = new String (octets);
Dans ce code, nous constatons trois processus de conversion de codage (un encodage, deux décodage). Regardons d'abord String.getTytes ():
octet public [] getBytes () {return stringcoding.encode (value, 0, value.length); }Appelez en interne la méthode stringcoding.encode ():
octet statique [] code (char [] ca, int off, int len) {String csn = charset.defaultCharset (). name (); Essayez {// Utilisez la variante de nom de charme encode () qui fournit la mise en cache. Retour Encoder (CSN, CA, OFF, LEN); } catch (UnportEnCoDingException x) {warnunSupportEdCharset (CSN); } essayez {return Encode ("ISO-8859-1", CA, OFF, LEN); } Catch (UnportEnCoDingException x) {// Si ce code est touché pendant l'initialisation de la machine virtuelle, les messages usutiles sont // la seule façon dont nous serons en mesure d'obtenir n'importe quel type de message d'erreur. MessageUtils.err ("ISO-8859-1 Charset non disponible:" + x.toString ()); // Si nous ne pouvons pas trouver ISO-8859-1 (un encodage requis), les choses // ont vraiment tort avec l'installation. System.exit (1); retourner null; }}La méthode Encode (char [] ParamArrayofchar, int Paramint1, intamint2) appelle d'abord le format de codage par défaut du système. Si le format de codage n'est pas spécifié, l'opération de codage est effectuée par défaut à l'aide du format de codage ISO-8859-1. L'approfondissement supplémentaire est le suivant:
String csn = (charSetName == null)? "ISO-8859-1": CharsetName;
Dans la même méthode, vous pouvez voir que le constructeur de la nouvelle chaîne est appelé la méthode stringcoding.decode ():
Public String (octets octets [], int offSet, int, charmet charset) {if (charset == null) lancez new nullpointerException ("charset"); Checkbounds (octets, décalage, longueur); this.value = stringcoding.decode (charse, octets, offset, longueur); } La méthode de décodage et le codent gèrent le format de codage de la même manière.
Pour les deux situations ci-dessus, nous n'avons qu'à définir un format de codage unifié, il n'y aura généralement pas de problèmes brouillés.
3. Format d'encodage et d'encodage
Tout d'abord, regardez le diagramme de classe de codage Java
Tout d'abord, définissez la classe ChartSet en fonction du graphique spécifié, puis créez l'objet ChartSetEncoder en fonction du plateau et appelez enfin charSetEncoder.encode pour coder la chaîne. Différents types d'encodage correspondent à une classe et le processus d'encodage réel est terminé dans ces classes. Le diagramme de synchronisation suivant montre le processus de codage détaillé:
Grâce à ce diagramme de classe codé et à ce diagramme de synchronisation, vous pouvez comprendre le processus de codage détaillé. Ce qui suit codera ISO-8859-1, GBK et UTF-8 via un code simple.
classe publique test02 {public static void main (String [] args) lève unportdencodingException {String String = "I Am CM"; Test02.printChart (String.toCharArray ()); Test02.printChart (string.getBytes ("ISO-8859-1")); Test02.printChart (string.getBytes ("gbk")); Test02.printChart (string.getBytes ("UTF-8")); } / ** * Convertir char en hexadecimal * / public static void printchart (char [] chars) {for (int i = 0; i <chars.length; i ++) {System.out.print (enter.tohexString (chars [i]) + ""); } System.out.println (""); } / ** * octet converti en hex * / public static void printchart (byte [] bytes) {for (int i = 0; i <bytes.length; i ++) {String hex = Integer.tohexString (bytes [i] & 0xff); if (hex.length () == 1) {hex = '0' + hex; } System.out.print (hex.touppercase () + ""); } System.out.println (""); }}Sortir:
6211 662f 20 63 6d 3f 3f 20 63 6d CE D2 CA C7 20 63 6d E6 88 91 E6 98 AF 20 63 6d
Grâce au programme, nous pouvons voir que le résultat de "Je suis CM" est:
Char []: 6211 662f 20 63 6d ISO-8859-1: 3f 3f 20 63 6d GBK: CE D2 CA C7 20 63 6D UTF-8: E6 88 91 E6 98 AF 20 63 6D 6D
L'image est la suivante: