1. Processo de conversão de codificação Java
Sempre usamos um arquivo de classe Java para interagir com os usuários mais diretamente (entrada, saída) e o texto contido nesses conteúdos interativos pode conter chinês. Se essas aulas de Java interagem com o banco de dados ou com a página front-end, seu ciclo de vida é sempre assim:
(1) Os programadores escrevem código do programa através de um editor no sistema operacional e salve o sistema operacional no formato de .java. Chamamos esses arquivos de arquivos de origem.
(2) Compilar esses arquivos de origem através do javac.exe no JDK para formar a classe .class.
(3) Execute essas classes diretamente ou implante -as em um contêiner da web para obter o resultado da saída.
Esses processos são observados da perspectiva macro e definitivamente não é possível entender isso. Precisamos realmente entender como o Java é codificado e decodificado:
Etapa 1: Quando usamos um editor para gravar um arquivo de origem Java, o arquivo do programa usará o formato de codificação padrão do sistema operacional (geralmente nosso sistema operacional chinês usa o formato de codificação GBK) para formar um arquivo .java. O arquivo de origem Java é salvo no formato de codificação do arquivo.Encoding suportado pelo sistema operacional por padrão. O código a seguir pode visualizar o arquivo do sistema do sistema.
System.out.println (System.getProperty ("file.encoding")); Etapa 2: quando usamos o javac.exe para compilar nosso arquivo Java, o JDK confirmará primeiro seu parâmetro de compilação que codifica para determinar o conjunto de caracteres do código -fonte. Se não especificarmos o parâmetro de compilação, o JDK obterá primeiro o parâmetro de file.Encoding do sistema operacional e, em seguida, o JDK converterá o programa de origem Java que escrevemos no File.Encoding Coding Format para o formato unicode padrão dentro de Java e o colocamos na memória.
Etapa 3: O JDK grava as informações compiladas e salvas sobre a memória acima no arquivo de classe para formar um arquivo .class. No momento, o arquivo .class é codificado Unicode, o que significa que o conteúdo em nossos arquivos .classe comum é convertido em formato de codificação Unicode, sejam eles caracteres chineses ou ingleses.
Nesta etapa, o método de manuseio dos arquivos de origem JSP é um pouco diferente: o contêiner da web chama o compilador JSP. O compilador JSP verificará primeiro se o arquivo JSP possui o formato de codificação de arquivo. Se não estiver definido, o compilador JSP ligará para o JDK para converter o arquivo JSP em uma classe de servlet temporária usando o método de codificação padrão e compilá -lo em um arquivo .class e mantê -lo em uma pasta temporária.
Etapa 4: Execute a classe compilada: haverá várias situações aqui
(1) execute diretamente no console.
(2) Classe JSP/Servlet.
(3) entre a classe Java e o banco de dados.
Cada uma dessas três situações terá diferentes maneiras de fazê -lo.
1. Classes em execução no console
Nesse caso, a JVM lerá primeiro o arquivo de classe salvo no sistema operacional na memória. No momento, o arquivo de classe na memória é codificado no Unicode e, em seguida, a JVM o executará. Se o usuário precisar inserir informações, a entrada de informações do usuário será codificada no formato do arquivo.Encoding e convertida em formato de codificação Unicode para salvá -lo na memória. Após a execução do programa, o resultado é convertido em formato de arquivo. Encodes e retornado ao sistema operacional e saída para a interface. Todo o processo é o seguinte:
Em todo o processo acima, nenhum erro pode ocorrer em qualquer conversão de codificação envolvida, caso contrário, ocorrerá um código ilegal.
2.Servlet Classe
Como os arquivos JSP serão convertidos em arquivos do servlet (mas o local de armazenamento é diferente), também incluiremos arquivos JSP aqui.
Quando um usuário solicita um servlet, o contêiner da web chama sua JVM para executar o servlet. Primeiro de tudo, a JVM carregará a classe Servlet na memória. O código do servlet na memória está no formato de codificação do Unicode. Então a JVM executa o servlet na memória. Durante a execução, se você precisar aceitar dados passados do cliente (como dados passados por formulários e URLs), o contêiner da Web aceitará os dados recebidos. Durante o processo de recepção, se o programa definir a codificação dos parâmetros recebidos, o formato de codificação de conjunto será adotado. Se não estiver definido, o formato de codificação ISO-8859-1 padrão será adotado. Após os dados recebidos, a JVM converterá o formato de codificação em Unicode e o armazenará na memória. Após a execução do servlet, os resultados da saída são gerados e o formato de codificação desses resultados de saída ainda é unicode. Imediatamente depois, o contêiner da web enviará diretamente a sequência de formato de codificação do Unicode gerado para o cliente. Se o programa especificar o formato de codificação no momento da saída, ele será emitido para o navegador de acordo com o formato de codificação especificado. Caso contrário, o formato de codificação ISO-8859-1 padrão é adotado. Todo o fluxograma de processo é o seguinte:
3. Parte do banco de dados
Sabemos que a conexão entre os programas Java e os bancos de dados está conectada através do driver JDBC e o driver JDBC padrão no formato de codificação ISO-8859-1. Ou seja, quando passamos dados para o banco de dados através do programa Java, o JDBC converterá primeiro os dados no formato Unicode que codifica no formato de codificação ISO-8859-1 e o armazena no banco de dados, ou seja, quando o banco de dados salva os dados, o formato padrão é ISO-8859-1.
2. Codificação e decodificação
A seguir, encerrará as operações de codificação e decodificação que o Java precisa executar nessas ocasiões e resolver o processo intermediário em detalhes para dominar ainda mais o processo de codificação e decodificação de Java. Existem quatro cenários principais em Java que requerem codificação e decodificação:
(1): Operação de E/S.
(2): Memória
(3): Banco de dados
(4): Javaweb
O seguinte apresenta principalmente os dois cenários anteriores. Enquanto a parte do banco de dados estiver definida corretamente, não haverá problema. Existem muitos cenários de Javaweb e você precisa entender a codificação de URL, obter, postar e servlet decodificar, de modo que a introdução da LZ do cenário Javaweb.
1.I/O operação
No LZ anterior mencionou que o problema ilegal não passa de inconsistência do formato de codificação durante o processo de transcodificação. Por exemplo, o UTF-8 é usado para a codificação e o GBK é usado para decodificar. No entanto, a razão mais fundamental é que há um problema com a conversão de caractere a byte ou byte em caracteres, e o principal cenário de conversão neste caso é a operação de E/S. Obviamente, as operações de E/S incluem principalmente a E/S da rede (ou seja, Javaweb) e E/S de disco. A E/S de rede é introduzida na próxima seção.
Primeiro, vejamos a operação de codificação de E/S.
O InputStream é a superclasse de todas as classes do fluxo de entrada de bytes, e o leitor é a classe abstrata do leitor. Java lê arquivos de uma maneira que é dividida em fluxo de bytes e por fluxo de caracteres. InputStream e Reader são as superclasses desses dois métodos de leitura.
Por byte, geralmente usamos o método inputStream.read () para ler bytes no fluxo de dados (read () lê apenas um byte de cada vez, que é muito lento. Normalmente usamos leitura (byte [])) e, em seguida, salve -o em uma matriz byte [] e finalmente convertemos para string. Quando lemos um arquivo, a codificação dos bytes depende do formato de codificação usado pelo arquivo e o problema de codificação também estará envolvido na conversão em processo de string. Se os formatos de codificação forem diferentes entre os dois, o problema poderá ocorrer. Por exemplo, há um problema que o formato de codificação Test.txt é UTF-8, portanto, o formato de codificação de fluxo de dados obtido ao ler um arquivo através de um fluxo de bytes é UTF-8. Se não especificarmos o formato de codificação durante a conversão em string, usamos o formato de codificação do sistema (GBK) por padrão para a decodificação. Como os formatos de codificação dos dois são inconsistentes, o código distorcido definitivamente ocorrerá no processo de construção da string, como segue:
Arquivo de arquivo = novo arquivo ("c: //test.txt"); InputStream input = new FileInputStream (arquivo); StringBuffer buffer = new StringBuffer (); byte [] bytes = novo byte [1024]; for (int n; (n = input.read (bytes))! =-1;) {buffer.append (new String (bytes, 0, n)); } System.out.println (buffer); O resultado da saída está iluminado ...
O conteúdo em test.txt é: eu sou cm.
Para evitar o código distorcido, especifique o formato de codificação durante o processo de construção de cordas, para que os formatos de codificação dos dois sejam consistentes durante a codificação e decodificação:
buffer.append (new string (bytes, 0, n, "utf-8"));
Por personagem, o fluxo de caracteres pode ser considerado como um fluxo de invólucro. Sua camada subjacente ainda usa um fluxo de bytes para ler bytes e, em seguida, decodifica os bytes de leitura em caracteres usando o método de codificação especificado. Em Java, o Reader é uma superclasse que lê fluxos de personagens. Portanto, da perspectiva inferior, não há diferença entre os arquivos de leitura por bytes e leitura por caractere. Ao ler, a leitura de personagens fica com bytes a cada vez, e os fluxos de bytes leem um byte de cada vez.
A conversão de byte e caracteres converte bytes em caracteres é essencialmente inputStreamReader. A API é explicada da seguinte forma: InputStreamReader é a ponte entre o fluxo de bytes para o fluxo de caracteres: lê bytes usando o charset especificado e os decodifica em caracteres. O conjunto de caracteres utilizado pode ser especificado ou explicitamente dado pelo nome, ou pode aceitar o conjunto de caracteres padrão da plataforma. Cada chamada para um método read () no InputStreamReader resulta em um ou mais bytes sendo lidos no fluxo de entrada subjacente. Para permitir a conversão eficaz de byte em caráter, você pode ler mais bytes do fluxo subjacente com antecedência, excedendo os bytes necessários para satisfazer a operação de leitura atual. A explicação da API é muito clara. O InputStreamReader ainda usa a leitura de bytes ao ler o arquivo na parte inferior. Depois de ler os bytes, ele precisa analisar os caracteres de acordo com um formato de codificação especificado. Se não houver formato de codificação especificado, ele adotará o formato de codificação padrão do sistema.
String file = "c: //test.txt"; String charset = "utf-8"; // Escreva caracteres para converter em byte stream fileOutputStream OutputStream = new FileOutputStream (FILE); OutputStreamWriter Writer = New OtpitStreamWriter (outputStream, charset); tente {writer.write ("eu sou cm"); } finalmente {writer.close (); } // leia bytes para converter em caracteres FileInputStream inputStream = new FileInputStream (File); InputStreamReader Reader = new InputStreamReader (InputStream, Charset); StringBuffer buffer = new StringBuffer (); char [] buf = novo char [64]; int conting = 0; tente {while (count = leitor.read (buf))! = -1) {buffer.append (buf, 0, contagem); }} finalmente {reader.close (); } System.out.println (buffer); 2. Memória
Primeiro, vejamos o seguinte código simples
String s = "eu sou cm"; byte [] bytes = s.getBytes (); String S1 = new String (bytes, "GBK"); String s2 = new string (bytes);
Neste código, vemos três processos de conversão de codificação (uma codificação, duas decodificações). Vejamos o String.getTytes () primeiro:
public byte [] getBytes () {return stringcoding.encode (value, 0, value.length); }Chame internamente o método StringCoding.Encode ():
byte estático [] codifica (char [] ca, int off, int len) {string csn = charset.defaultcharset (). name (); tente {// use o nome do charset code () variante que fornece armazenamento em cache. Return Encody (CSN, CA, Off, Len); } Catch (UnsupportEdEncodingException x) {WarnUnsupportEdCharset (CSN); } tente {return code ("ISO-8859-1", CA, OFF, LEN); } Catch (UnsupportEdEncodingException x) {// Se este código for atingido durante a inicialização da VM, o MessageUtils é // a única maneira de conseguirmos obter qualquer tipo de mensagem de erro. MessageUtils.err ("ISO-8859-1 charset não disponível:" + x.toString ()); // Se não conseguirmos encontrar ISO-8859-1 (uma codificação necessária), as coisas // estão seriamente erradas com a instalação. System.Exit (1); retornar nulo; }}O método codificador (char [] paramearrayofchar, int paramint1, int paramint2) chama primeiro o formato de codificação padrão do sistema. Se o formato de codificação não for especificado, a operação de codificação será realizada por padrão usando o formato de codificação ISO-8859-1. Mais aprofundamento é o seguinte:
String csn = (charsetName == null)? "ISO-8859-1": CharsetName;
No mesmo método, você pode ver que o construtor da nova string é chamado de método StringCoding.Decode ():
public string (byte bytes [], int offset, int length, charset charset) {if (charset == null) lança nova nullPointerException ("charset"); Verificação de bytes (bytes, deslocamento, comprimento); this.value = stringcoding.decode (charset, bytes, deslocamento, comprimento); } O método de decodificação e codificar lidar com o formato de codificação da mesma maneira.
Para as duas situações acima, precisamos definir apenas um formato de codificação unificado, geralmente não haverá problemas ilegíveis.
3. Formato de codificação e codificação
Primeiro, veja o diagrama de classe de codificação Java
Primeiro, defina a classe ChartSet de acordo com o gráfico especificado e, em seguida, crie o objeto ChartSetEnCoder de acordo com o ChartSet e, finalmente, ligue para o charsetEncoder.Encode para codificar a string. Diferentes tipos de codificação corresponderão a uma classe e o processo de codificação real é concluído nessas classes. O diagrama de tempo seguinte mostra o processo de codificação detalhado:
Através deste diagrama de classe codificado e diagrama de tempo, você pode entender o processo de codificação detalhado. O seguinte codificará ISO-8859-1, GBK e UTF-8 através de um código simples.
classe pública test02 {public static void main (string [] args) lança UnsupportEnCodingException {string string = "eu sou cm"; Test02.printChart (string.toCharArray ()); Test02.printChart (string.getbytes ("ISO-8859-1")); Test02.printChart (string.getbytes ("gbk")); Test02.printChart (string.getbytes ("utf-8")); } / *** Converta char em hexadecimal* / public static void printChart (char [] chars) {for (int i = 0; i <chars.length; i ++) {System.out.print (Integer.tohexstring (chars [i])+""); } System.out.println (""); } / ** * Byte convertido em hexadecimal * / public static void printChart (byte [] bytes) {for (int i = 0; i <bytes.length; i ++) {string hex = integer.tohexstring (bytes [i] e 0xff); if (hex.Length () == 1) {hex = '0' + hex; } System.out.print (hex.touppercase () + ""); } System.out.println (""); }}Saída:
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
Através do programa, podemos ver que o resultado de "I Am CM" é:
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
A imagem é a seguinte: