1. Java 인코딩 변환 프로세스
우리는 항상 Java 클래스 파일을 사용하여 사용자와 가장 직접적으로 상호 작용하고 (입력, 출력), 이러한 대화 형 콘텐츠에 포함 된 텍스트에는 중국어가 포함될 수 있습니다. 이 Java 클래스는 데이터베이스와 상호 작용하든 프론트 엔드 페이지와 상호 작용하든, 수명주기는 항상 다음과 같습니다.
(1) 프로그래머는 운영 체제의 편집기를 통해 프로그램 코드를 작성하고 운영 체제를 .java 형식으로 저장합니다. 이 파일을 소스 파일이라고합니다.
(2) JDK의 javac.exe를 통해 이러한 소스 파일을 컴파일하여 .class 클래스를 형성합니다.
(3)이 클래스를 직접 실행하거나 웹 컨테이너에 배치하여 출력 결과를 얻으십시오.
이러한 과정은 거시적 관점에서 관찰되며,이를 이해하는 것은 불가능합니다. 우리는 Java가 어떻게 인코딩되고 디코딩되는지 진정으로 이해해야합니다.
1 단계 : 편집기를 사용하여 Java 소스 파일을 작성하면 프로그램 파일은 운영 체제의 기본 인코딩 형식을 사용합니다 (일반적으로 중국 운영 체제는 GBK 인코딩 형식을 사용하여 .java 파일을 형성합니다. Java 소스 파일은 파일에 저장됩니다. ENCODING 인코딩 형식은 운영 체제에서 기본적으로 지원합니다. 다음 코드는 시스템 파일을 볼 수 있습니다. 인코딩 매개 변수 값.
System.out.println (System.GetProperty ( "file.encoding"));
2 단계 : Javac.exe를 사용하여 Java 파일을 컴파일하면 JDK는 먼저 소스 코드 문자 세트를 결정하기 위해 컴파일 매개 변수 인코딩을 확인합니다. 컴파일 매개 변수를 지정하지 않으면 JDK는 먼저 운영 체제의 기본 파일을 얻은 다음 JDK는 파일에서 작성한 Java 소스 프로그램을 변환하여 인코딩 형식을 Java 내부의 기본 유니 코드 형식으로 변환하여 메모리에 넣습니다.
3 단계 : JDK는 위의 메모리에 대한 컴파일 및 저장된 정보를 클래스 파일에 작성하여 .class 파일을 작성합니다. 이 시점에서 .class 파일은 유니 코드 인코딩되어 공통 .class 파일의 내용이 중국어 또는 영어 문자이든 유니 코드 인코딩 형식으로 변환됩니다.
이 단계에서는 JSP 소스 파일의 처리 방법이 약간 다릅니다. 웹 컨테이너는 JSP 컴파일러를 호출합니다. JSP 컴파일러는 먼저 JSP 파일에 파일 인코딩 형식이 있는지 확인합니다. 설정되지 않은 경우 JSP 컴파일러는 JDK를 호출하여 기본 인코딩 메소드를 사용하여 JSP 파일을 임시 서블릿 클래스로 변환 한 다음 .class 파일로 컴파일하고 임시 폴더에 보관합니다.
4 단계 : 컴파일 된 클래스 실행 : 여기에 몇 가지 상황이 있습니다.
(1) 콘솔에서 직접 실행하십시오.
(2) JSP/Servlet 클래스.
(3) Java 클래스와 데이터베이스 사이.
이 세 가지 상황은 각각 다른 방법을 가질 것입니다.
1. 콘솔에서 실행되는 클래스
이 경우 JVM은 먼저 운영 체제에 저장된 클래스 파일을 메모리에 읽습니다. 현재 메모리의 클래스 파일은 유니 코드로 인코딩 된 다음 JVM이 실행됩니다. 사용자가 정보를 입력 해야하는 경우 사용자의 정보 입력은 파일에 인코딩되고 유니 코드 인코딩 형식으로 변환되어 메모리에 저장됩니다. 프로그램이 실행되면 결과는 파일 인코딩 형식으로 변환되어 운영 체제로 돌아와 인터페이스로 출력됩니다. 전체 프로세스는 다음과 같습니다.
위의 전체 프로세스에서는 관련된 인코딩 변환에서 오류가 발생할 수 없습니다. 그렇지 않으면 차량 코드가 발생합니다.
2. 서비스 수업
JSP 파일은 결국 서블릿 파일로 변환되므로 (스토리지 위치는 다릅니다) 여기에 JSP 파일도 포함됩니다.
사용자가 서블릿을 요청하면 웹 컨테이너는 JVM을 호출하여 서블릿을 실행합니다. 우선, JVM은 서블릿 클래스를 메모리에로드합니다. 메모리의 서블릿 코드는 유니 코드 인코딩 형식입니다. 그런 다음 JVM은 서블릿을 메모리에서 실행합니다. 실행 중에 클라이언트에서 전달 된 데이터 (예 : 양식 및 URL에 전달 된 데이터)로부터 전달 된 데이터를 수락 해야하는 경우 웹 컨테이너는 들어오는 데이터를 수락합니다. 수신 과정에서 프로그램이 들어오는 매개 변수의 인코딩을 설정하면 세트 인코딩 형식이 채택됩니다. 설정되지 않은 경우 기본 ISO-8859-1 인코딩 형식이 채택됩니다. 수신 된 데이터 후에 JVM은 인코딩 형식을 유니 코드로 변환하여 메모리에 저장합니다. 서블릿을 실행 한 후 출력 결과가 생성되고 이러한 출력 결과의 인코딩 형식은 여전히 유니 코드입니다. 그 후 즉시 웹 컨테이너는 생성 된 유니 코드 인코딩 형식 문자열을 클라이언트로 직접 보냅니다. 프로그램이 출력시 인코딩 형식을 지정하면 지정된 인코딩 형식에 따라 브라우저로 출력됩니다. 그렇지 않으면 기본 ISO-8859-1 인코딩 형식이 채택됩니다. 전체 프로세스 흐름도는 다음과 같습니다.
3. 데이터베이스 부분
Java 프로그램과 데이터베이스 간의 연결은 JDBC 드라이버를 통해 연결되어 있으며 JDBC 드라이버 기본값은 ISO-8859-1 인코딩 형식으로 기본적으로 기본적으로 연결됩니다. 즉, Java 프로그램을 통해 데이터를 데이터베이스로 전달할 때 JDBC는 먼저 유니 코드 인코딩 형식의 데이터를 ISO-8859-1 인코딩 형식으로 변환 한 다음 데이터베이스가 데이터를 저장할 때, 즉 Default Format은 ISO-8859-1입니다.
2. 인코딩 및 디코딩
다음은 Java가 그러한 경우에 수행 해야하는 인코딩 및 디코딩 작업을 종료하고 Java의 인코딩 및 디코딩 프로세스를 추가로 마스터하기 위해 중간 프로세스를 상세하게 분류합니다. Java에는 인코딩 및 디코딩이 필요한 네 가지 주요 시나리오가 있습니다.
(1) : I/O 작동
(2) : 메모리
(3) : 데이터베이스
(4) : Javaweb
다음은 주로 이전 두 시나리오를 소개합니다. 데이터베이스 부품이 올바르게 설정된 한 문제가 없습니다. Javaweb 시나리오가 너무 많아 URL, Get, Post 및 Servlet Decoding의 인코딩을 이해해야하므로 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.read () 메소드를 사용하여 데이터 스트림에서 바이트를 읽습니다 (읽기 ()는 한 번에 하나의 바이트 만 읽습니다. 매우 느립니다. 일반적으로 read (byte [])을 사용한 다음 바이트 [] 배열로 저장 한 다음 마침내 문자열로 변환합니다. 파일을 읽을 때 바이트 인코딩은 파일에서 사용하는 인코딩 형식에 따라 다르며 인코딩 문제는 문자열 프로세스로 변환에 관여합니다. 인코딩 형식이 둘 사이에 다른 경우 문제가 발생할 수 있습니다. 예를 들어, Test.txt 인코딩 형식이 UTF-8이므로 바이트 스트림을 통해 파일을 읽을 때 얻은 데이터 스트림 인코딩 형식이 UTF-8이라는 문제가 있습니다. 문자열로 변환하는 동안 인코딩 형식을 지정하지 않으면 기본적으로 시스템 인코딩 형식 (GBK)을 디코딩으로 사용합니다. 이 둘의 인코딩 형식은 일관성이 없기 때문에 다음과 같이 문자열을 구성하는 과정에서 분명한 코드가 반드시 발생합니다.
파일 = 새 파일 ( "c : //test.txt"); inputStream input = 새 FileInputStream (파일); StringBuffer buffer = new StringBuffer (); 바이트 [] 바이트 = 새로운 바이트 [1024]; for (int n; (n = input.read (bytes))! = -1;) {buffer.append (new String (bytes, 0, n)); } system.out.println (버퍼); 출력 결과가 밝혀졌습니다 ...
Test.txt의 내용은 다음과 같습니다. 저는 CM입니다.
차량 코드를 피하려면 문자열 구성 프로세스 중에 인코딩 형식을 지정하여 인코딩 및 디코딩 중에 두 인코딩 형식이 일관되도록하십시오.
buffer.append (새 문자열 (바이트, 0, n, "UTF-8"));
캐릭터에 따라 문자 스트림은 래퍼 스트림으로 간주 될 수 있습니다. 그 기본 레이어는 여전히 바이트 스트림을 사용하여 읽기 바이트를 사용한 다음 지정된 인코딩 방법을 사용하여 읽기 바이트를 문자로 디코딩합니다. Java에서 독자는 캐릭터 스트림을 읽는 슈퍼 클래스입니다. 따라서 바닥 관점에서 바이트 별 파일을 읽는 것과 문자 별 읽기 사이에는 차이가 없습니다. 읽을 때 문자 읽기는 매번 바이트가 남아 있으며 바이트 스트림에는 한 번에 하나의 바이트를 읽습니다.
바이트 및 캐릭터 변환 바이트 변환 바이트는 본질적으로 입력 스트림 리더입니다. API는 다음과 같이 설명됩니다. InputStreamReader는 바이트 스트림의 문자 스트림 사이의 브리지입니다. 지정된 숯을 사용하여 바이트를 읽고 문자로 디코딩합니다. 사용하는 문자 세트는 이름으로 지정되거나 명시 적으로 제공 될 수 있거나 플랫폼의 기본 문자 세트를 허용 할 수 있습니다. inputStreamReader의 read () 메소드로의 각 호출은 기본 입력 스트림에서 하나 이상의 바이트를 읽습니다. 바이트에서 문자로 효과적인 변환을 가능하게하려면 기본 스트림에서 더 많은 바이트를 미리 읽을 수 있으며 현재 읽기 작업을 충족시키는 데 필요한 바이트를 초과합니다. API 설명은 매우 명확합니다. inputStreamReader는 하단의 파일을 읽을 때 여전히 바이트 읽기를 사용합니다. 바이트를 읽은 후 지정된 인코딩 형식에 따라 문자로 구문 분석해야합니다. 지정된 인코딩 형식이 없으면 시스템 기본 인코딩 형식을 채택합니다.
문자열 파일 = "c : //test.txt"; 문자열 charset = "utf-8"; // 바이트 스트림으로 변환 할 문자를 쓰기 FileOutStream outputStream = 새 FileOutputStream (파일); OutputStreamWriter Writer = New OutputStreamWriter (OutputStream, Charset); try {writer.write ( "i am cm"); } 마침내 {writer.close (); } // 문자로 변환 할 바이트를 읽습니다. fileInputStream inputStream = new FileInputStream (파일); inputStreamReader reader = 새로운 입력 스트리 프 리조더 (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입니다"; 바이트 [] bytes = s.getBytes (); 문자열 s1 = 새 문자열 (바이트, "gbk"); 문자열 s2 = 새 문자열 (바이트);
이 코드에서는 세 가지 인코딩 변환 프로세스 (하나의 인코딩, 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.defaultcharset (). name (); {// 캐싱을 제공하는 charset name encode () 변형을 사용해보십시오. 리턴 엔코드 (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); 널 리턴; }}Encode (char [] paramarrayofchar, int paramint1, int paramint2) 메소드는 먼저 시스템의 기본 인코딩 형식을 호출합니다. 인코딩 형식이 지정되지 않은 경우 ISO-8859-1 인코딩 형식을 사용하여 인코딩 작업이 기본적으로 수행됩니다. 더 심화는 다음과 같습니다.
문자열 csn = (charsetname == null)? "ISO-8859-1": charsetname;
동일한 메소드에서 새 문자열의 생성자를 StringCoding.decode () 메소드라고합니다.
public String (바이트 바이트 [], int 오프셋, int 길이, charset charset) {if (charset == null) 던질 새 nullpointerexception ( "charset"); 체크 바운드 (바이트, 오프셋, 길이); this.value = stringCoding.Decode (charset, bytes, 오프셋, 길이); } 디코드 메소드와 인코딩은 인코딩 형식을 동일한 방식으로 처리합니다.
위의 두 상황에서는 통합 인코딩 형식 만 설정하면 일반적으로 문제가 없습니다.
3. 인코딩 및 인코딩 형식
먼저 Java 인코딩 클래스 다이어그램을보십시오
먼저 지정된 차트에 따라 ChartSet 클래스를 설정 한 다음 ChartSet에 따라 ChartSetEncoder 객체를 작성하고 마지막으로 charSetencoder.encode를 호출하여 문자열을 인코딩하십시오. 다른 인코딩 유형은 클래스에 해당하며 실제 인코딩 프로세스는이 클래스에서 완료됩니다. 다음 타이밍 다이어그램은 자세한 인코딩 프로세스를 보여줍니다.
이 코딩 된 클래스 다이어그램 및 타이밍 다이어그램을 통해 자세한 인코딩 프로세스를 이해할 수 있습니다. 다음은 간단한 코드를 통해 ISO-8859-1, GBK 및 UTF-8을 인코딩합니다.
public class test02 {public static void main (string [] args)은 unsupportedencodingexception {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를 16 진수로 변환* / public static void printchart (char [] chars) {for (int i = 0; i <chars.length; i ++) {system.out.print (integer.tohexstring (chars [i])+""); } system.out.println ( ""); } / ** * 바이트는 16 진수로 변환 * / 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
그림은 다음과 같습니다.