1.変換プロセスのJavaエンコード
Javaクラスファイルを常に使用して、ユーザーと最も直接的に対話し(入力、出力)、これらのインタラクティブコンテンツに含まれるテキストには中国語が含まれている場合があります。これらのJavaクラスがデータベースと相互作用する場合でも、フロントエンドページと相互作用する場合でも、ライフサイクルは常に次のようなものです。
(1)プログラマーは、オペレーティングシステムのエディターを介してプログラムコードを作成し、.javaの形式でオペレーティングシステムを保存します。これらのファイルをソースファイルと呼びます。
(2)jdkのjavac.exeを介してこれらのソースファイルをコンパイルして、.classクラスを形成します。
(3)これらのクラスを直接実行するか、Webコンテナに展開して出力結果を取得します。
これらのプロセスはマクロの観点から観察されており、これを理解することは絶対に不可能です。 Javaのエンコードとデコードの方法を本当に理解する必要があります。
ステップ1:エディターを使用してJavaソースファイルを書き込むと、プログラムファイルはオペレーティングシステムのデフォルトエンコード形式(通常、中国のオペレーティングシステムはGBKエンコード形式を使用)を使用して.javaファイルを形成します。 Javaソースファイルは、デフォルトでオペレーティングシステムでサポートされているエンコード形式をエンコードするfile.Encodingエンコード形式に保存されます。次のコードでは、システムのファイルをエンコードパラメーター値を表示できます。
System.out.println(system.getProperty( "file.Encoding"));
ステップ2:javac.exeを使用してJavaファイルをコンパイルすると、JDKはまずコンピレーションパラメーターエンコードを確認してソースコード文字セットを決定します。コンピレーションパラメーターを指定しない場合、JDKは最初にオペレーティングシステムのデフォルトfile.Encodingパラメーターを取得し、JDKはfile.Encodingエンコード形式にjava内のデフォルトのユニコード形式に記憶してメモリに置いたJavaソースプログラムを変換します。
ステップ3:JDKは、上記のメモリに関するコンパイルされた情報と保存された情報をクラスファイルに書き込み、クラスファイルを形成します。この時点で、.classファイルはUnicodeエンコードされています。つまり、一般的な.classファイルの内容は、中国語であろうと英語の文字であろうと、Unicodeエンコード形式に変換されます。
このステップでは、JSPソースファイルの処理方法は少し異なります。WebコンテナはJSPコンパイラを呼び出します。 JSPコンパイラは、最初にJSPファイルにファイルエンコード形式があるかどうかを確認します。設定されていない場合、JSPコンパイラはJDKを呼び出して、デフォルトのエンコードメソッドを使用してJSPファイルを一時サーブレットクラスに変換し、。クラスファイルにコンパイルし、一時フォルダーに保持します。
ステップ4:コンパイルされたクラスを実行する:ここにいくつかの状況があります
(1)コンソールで直接実行します。
(2)JSP/サーブレットクラス。
(3)Javaクラスとデータベースの間。
これらの3つの状況にはそれぞれ、それを行うさまざまな方法があります。
1。コンソールで実行されるクラス
この場合、JVMは最初にオペレーティングシステムに保存されたクラスファイルをメモリに読み取ります。この時点で、メモリ内のクラスファイルはUnicodeでエンコードされ、JVMが実行されます。ユーザーが情報を入力する必要がある場合、ユーザーによる情報入力はfile.Encoding形式でエンコードされ、Unicodeエンコード形式に変換され、メモリに保存されます。プログラムが実行された後、結果はfile.Encoding形式に変換され、オペレーティングシステムに戻り、インターフェイスに出力されます。プロセス全体が次のとおりです。
上記のプロセス全体では、関与するエンコード変換でエラーが発生することはありません。そうしないと、文字化けコードが発生します。
2.サーブレットクラス
JSPファイルは最終的にサーブレットファイルに変換されるため(ただし、ストレージの場所は異なります)、JSPファイルもここに含まれます。
ユーザーがサーブレットを要求すると、WebコンテナはJVMを呼び出してサーブレットを実行します。まず、JVMはサーブレットクラスをメモリにロードします。メモリ内のサーブレットコードは、Unicodeエンコード形式です。次に、JVMはメモリでサーブレットを実行します。実行中、クライアントから渡されたデータ(フォームやURLで渡されたデータなど)を受け入れる必要がある場合、Webコンテナは着信データを受け入れます。受信プロセス中に、プログラムが着信パラメーターのエンコードを設定する場合、セットエンコード形式が採用されます。設定されていない場合、デフォルトのISO-8859-1エンコード形式が採用されています。受信したデータの後、JVMはエンコード形式をUnicodeに変換し、メモリに保存します。サーブレットを実行した後、出力結果が生成され、これらの出力結果のエンコード形式はまだユニコードです。その後、Webコンテナは、生成されたUnicodeエンコード形式の形式をクライアントに直接送信します。プログラムが出力時にエンコード形式を指定すると、指定されたエンコード形式に従ってブラウザに出力されます。それ以外の場合、デフォルトのISO-8859-1エンコード形式が採用されています。プロセスフローチャート全体は次のとおりです。
3.データベースパーツ
Javaプログラムとデータベース間の接続はJDBCドライバーを介して接続されており、JDBCドライバーはISO-8859-1エンコーディング形式にデフォルトであることがわかります。つまり、Javaプログラムを介してデータをデータベースに渡すと、JDBCは最初にUnicodeエンコード形式のデータをISO-8859-1エンコード形式に変換し、データベースにデータを保存すると、デフォルトのフォーマットがISO-8859-1です。
2。エンコーディングとデコード
以下は、Javaがこれらの機会に実行する必要があるエンコードおよびデコード操作を終了し、Javaのエンコードとデコードプロセスをさらにマスターするために中間プロセスを詳細に整理します。 Javaには、エンコードとデコードが必要な4つの主要なシナリオがあります。
(1):I/O操作
(2):メモリ
(3):データベース
(4):Javaweb
以下は、主に前の2つのシナリオを紹介します。データベースパーツが正しく設定されている限り、問題はありません。 Javawebのシナリオが多すぎるため、URL、Get、Post、およびサーブレットデコードのエンコードを理解する必要があるため、LZはJavawebシナリオの導入です。
1.I/O操作
前のLZで、文字化けの問題はトランスコーディングプロセス中のエンコード形式の矛盾にすぎないと述べました。たとえば、UTF-8はエンコードに使用され、GBKはデコードに使用されます。ただし、最も基本的な理由は、キャラクターからバイトまたはバイト間変換に問題があることであり、この場合の変換の主なシナリオはI/O操作です。もちろん、I/O操作には主にネットワークI/O(つまり、Javaweb)とディスクI/Oが含まれます。ネットワークI/Oは次のセクションで紹介します。
まず、I/Oエンコード操作を見てみましょう。
inputstreamは、バイト入力ストリームのすべてのクラスのスーパークラスであり、リーダーはリーダーの抽象クラスです。 Javaは、バイトストリームと文字ストリームによって分割される方法でファイルを読み取ります。 InputStreamとReaderは、これら2つの読み取り方法のスーパークラスです。
バイトでは、通常、inputstream.read()メソッドを使用してデータストリームのバイト(read()は一度に1つのバイトのみを読み取ります。これは非常に遅いです。通常はread(byte []))を使用し、バイト[]配列に保存し、最後に弦に変換します。ファイルを読むと、バイトのエンコードはファイルで使用されるエンコード形式に依存し、エンコードの問題は文字列への変換にも関与します。 2つの間でエンコード形式が異なる場合、問題が発生する可能性があります。たとえば、test.txtエンコード形式がUTF-8であるという問題があるため、バイトストリームを介してファイルを読み取るときに取得されるデータストリームエンコード形式はUTF-8です。文字列への変換中にエンコーディング形式を指定しない場合、デフォルトでデコードにシステムをエンコード形式(GBK)を使用します。 2つのエンコード形式は一貫していないため、次のように、文字列の構築プロセスで文字化けコードは間違いなく発生します。
file file = new file( "c://test.txt"); inputstream input = new fileinputStream(file); stringbuffer buffer = new StringBuffer(); byte [] bytes = new byte [1024]; for(int n;(n = input.read(bytes))!= -1;){buffer.append(new String(bytes、0、n)); } system.out.println(バッファー);出力の結果は文字化けしています...
test.txtのコンテンツは次のとおりです。私はCMです。
文字化けコードを回避するには、文字列構築プロセス中にエンコード形式を指定して、2つのエンコード形式がエンコードとデコード中に一貫しているようにします。
buffer.append(new String(bytes、0、n、 "utf-8"));
キャラクターによって、文字ストリームはラッパーストリームと見なすことができます。その基礎となるレイヤーは、バイトストリームを使用して読み取りバイトを使用しており、指定されたエンコードメソッドを使用して読み取りバイトを文字にデコードします。 Javaでは、読者は文字ストリームを読むスーパークラスです。したがって、一番下の観点からは、バイトでファイルを読むこととキャラクターによる読み取りの間に違いはありません。読み取りのとき、キャラクターの読みは毎回バイトが残され、バイトストリームは一度に1つのバイトを読み取ります。
バイトと文字の変換バイトを文字に変換することは、基本的に入力ストリームリーダーです。 APIは次のように説明されています:inputstreamReaderは、バイトストリーム間の文字ストリーム間のブリッジです。指定されたcharsetを使用してバイトを読み取り、文字にデコードします。使用する文字セットは、名前で指定または明示的に与えられるか、プラットフォームのデフォルトの文字セットを受け入れることができます。 inputstreamReaderのread()メソッドへの各呼び出しは、基礎となる入力ストリームから1つ以上のバイトが読み取られます。バイトからキャラクターへの効果的な変換を有効にするために、現在の読み取り操作を満たすために必要なバイトを超えて、基礎となるストリームのバイトを事前に読むことができます。 APIの説明は非常に明確です。 inputStreamReaderは、下部のファイルを読み取るときにバイトの読み取りを使用します。バイトを読んだ後、指定されたエンコード形式に従って文字に分析する必要があります。指定されたエンコード形式がない場合、システムのデフォルトエンコード形式を採用します。
文字列file = "c://test.txt";文字列charset = "utf-8"; //バイトストリームに変換する文字を書き込みますfileoutputStream outputStream = new fileoutputStream(file); outputStreamWriter writer = new outputStreamWriter(outputStream、charset); try {writer.write( "i are cm"); }最後に{writer.close(); } //バイトを読み取り、文字に変換するfileinputStream inputstream = new fileinputStream(file); inputStreamReader reader = new inputStreamReader(inputStream、charset); stringbuffer buffer = new StringBuffer(); char [] buf = new char [64]; int count = 0; try {while((count = reader.read(buf))!= -1){buffer.append(buf、0、count); }}最後に{reader.close(); } system.out.println(バッファー); 2。メモリ
まず、次の簡単なコードを見てみましょう
文字列s = "私はcm"; byte [] bytes = s.getBytes();文字列s1 = new String(bytes、 "gbk");文字列s2 = new String(バイト);
このコードでは、3つのエンコード変換プロセス(1つのエンコード、2つのデコード)が表示されます。 string.gettytes()を見てみましょう。
public byte [] getBytes(){return StringCoding.encode(value、0、value.length); }内部的にStringCoding.Encode()メソッドを呼び出します:
static byte [] encode(char [] ca、int off、int len){string csn = charset.defaultharset()。name(); try {//キャッシュを提供するcharset name encode()バリアントを使用します。 returnエンコード(CSN、CA、OFF、LEN); } catch(unsupportedencodingexception x){warnunsupportedcharset(csn); } try {return encode( "iso-8859-1"、ca、off、len); } catch(unsupportedencodingexception x){//このコードがVM初期化中にヒットした場合、messageutilsは//あらゆる種類のエラーメッセージを取得できる唯一の方法です。 messageutils.err( "ISO-8859-1 CHARSETは使用できません:" + x.toString()); // ISO-8859-1(必要なエンコード)が見つからない場合、//インストールが非常に間違っています。 System.Exit(1); nullを返します。 }}エンコード(char [] paramarrayofchar、int paramint1、int paramint2)メソッドは、最初にシステムのデフォルトエンコード形式を呼び出します。エンコード形式が指定されていない場合、エンコード操作は、ISO-8859-1エンコード形式を使用してデフォルトで実行されます。さらに深化は次のとおりです。
文字列csn =(charsetname == null)? 「ISO-8859-1」:CharSetName;
同じ方法では、新しい文字列のコンストラクターがstringCoding.decode()メソッドと呼ばれることがわかります。
public string(byte bytes []、int offset、int length、charset charset){if(charset == null)throw new nullpointerexception( "charset");チェックバウンド(バイト、オフセット、長さ); this.value = stringCoding.decode(charset、bytes、offset、length); }デコードメソッドとエンコードは、エンコード形式を同じ方法で処理します。
上記の2つの状況では、統一されたエンコード形式を設定する必要があります。一般に、文字化けの問題はありません。
3。エンコードおよびエンコード形式
まず、クラス図をエンコードするJavaをご覧ください
最初に、指定されたチャートに従ってチャートセットクラスを設定し、チャートセットに従ってチャートセンコーダーオブジェクトを作成し、最後にcharsetencoder.encodeを呼び出して文字列をエンコードします。さまざまなエンコーディングタイプがクラスに対応し、実際のエンコードプロセスはこれらのクラスで完了します。次のタイミング図は、詳細なエンコーディングプロセスを示しています。
このコード化されたクラス図とタイミング図を使用すると、詳細なエンコードプロセスを理解できます。以下は、単純なコードを介してISO-8859-1、GBK、およびUTF-8をエンコードします。
public class test02 {public static void main(string [] args)throws unsupportedencodincection {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")); } / *** charを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( ""); } / ** * 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( ""); }}出力:
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
プログラムを通じて、「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
写真は次のとおりです。