Java編碼問題

最近在看,How Tomcat Works,反正感覺上就是叼叼的,看完第一章就想自己寫個服務器出來了,大概原理應該弄得差不多了:客戶端與服務器端通訊,不管是什麼B/S,C/S啊,都是在通訊,通訊就是交換信息,就像是兩個人交流,你給我發消息,我給你發消息。但是因爲這兩個人有可能是不同地區的人,他們將不同的語言,所以制定了一系列的交流的規則,首先說什麼,然後說什麼,不能說什麼……這就是協議,web層通訊採用的最多的就是HTTP協議,協議向下封裝,什麼底層透明性那些就不說了,,,反正到最後在電線中傳播的都是0101010101這樣的字符串了,物理上使用高低電壓表示的,但是我就不知道在光纜、空氣等傳輸介質中是怎麼表示的呢,但是最後客戶端、服務器端接收到的信息都是010101,就是所謂的字節流(bit),然後將這些字節流按編碼(GBK、UTF-8)規則翻譯成人能夠輕鬆識別的語言,就這樣了。接着我的問題就來了:


問題描述:我在一個java文件中寫了中文字符,並將這些字符輸出到客戶端,但是客戶端總是顯示不出來。

問題探索:我寫的java文件是會保存到物理磁盤的,這樣保存時會有一個編碼選擇,但是我的客戶端訪問這個程序時是訪問已編譯後的字節碼文件啊,就是那個.class文件。我先講java文件以UTF-8編碼格式保存,然後訪問那個.class文件,看客戶端的輸出,然後將java文件以GBK編碼格式保存,再試,結果就是設置瀏覽器的編碼爲GB2312(GBK的簡化版)時,我java代碼中的中文能正常顯示在瀏覽器中,瀏覽器的編碼設置爲UTF-8時,網頁顯示亂碼,我輸出的方式是直接從socket上獲取的OutputStream對象,這就是字節流,就是直接將010101輸出到了客戶端,由客戶決定採用哪種編碼去顯示。


我輸出的中文:

<span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">	@Override
	public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
		System.out.println("servlet service開始執行.");
		PrintWriter printWriter=res.getWriter();
		printWriter.println("你好,小王子~");
		printWriter.print("你從哪裏來的呀~");
		System.out.println("haha~");
	}</span></span></span>


其中PrintWriter是將output對象包裝了一下:

<span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">	@Override
	public PrintWriter getWriter() throws IOException {
		printWriter=new PrintWriter(output,true);
		return printWriter;
	}</span></span></span>

output是從socket上直接獲取的:

<span style="font-size:14px;"><span style="font-size:14px;">OutputStream output=socket.getOutputStream();</span></span>


然後我發現就是java文件保存的編碼格式與編譯後的.class文件無關,我想是不是.class文件沒有所謂的編碼,,,,


哎呀,寫着寫着,又發現問題了,就是PrintWriter不知道有沒有對中文進行編碼?


反正我都試了,懶得細說了,直接用output輸出,也是一樣的,


最後的結論就是:java文件編譯生成得.class文件是無所謂編碼的,就是與java文件保存的編碼格式無關。。。。但我還是不知道這是怎麼實現的?


……以上結論無效,,徹底混亂啦!


-------------------------------------------------------------

更新:

結論:只與獲取到socket對象的所在代碼文件的編碼有關,就是在該代碼存在的文件中,該文件以什麼格式保存,則輸出到客戶端的格式就是什麼樣的。

該測試的簡化代碼如下:

<span style="font-size:14px;"><span style="font-size:14px;">package test;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;
import java.net.UnknownHostException;

import javax.servlet.Servlet;

public class HttpServer {

	public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";


	private boolean shutdown = false;

	public static void main(String[] args) {
		HttpServer server = new HttpServer();
		System.out.println(WEB_ROOT+"\n");
		server.await();
	}

	private void await() {
		ServerSocket serverSocket = null;
		int port = 8088;
		try {
			serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(1);
		}

		while (!shutdown) {
			Socket socket = null;
			OutputStream output = null;
			Response response=null;

			try {
				socket = serverSocket.accept();
				output=socket.getOutputStream();
				response=new Response(output);
				
				output.write("小王子11".getBytes());
				
				URL[] urls=new URL[1];
				URLStreamHandler urlStreamHandler = null;
				File classPath = new File("G:\\HowTomcatWorks\\JavaWebServer\\webroot");
				String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString();
				System.out.println(repository);
				urls[0] = new URL(null, repository, urlStreamHandler);
				URLClassLoader loader =new URLClassLoader(urls);
				Class myClass = null;
				try {
					myClass = loader.loadClass("TestServlet");
					Servlet servlet = (Servlet) myClass.newInstance();
					servlet.service( null, response);
				} catch (Exception e) {
					e.printStackTrace();
				}
				socket.close();
				
			} catch (IOException e) {
				e.printStackTrace();
				continue;
			}
		}
	}

}
</span></span>


然後我又發現了一個問題:本來我是想加載指定目錄下的class文件的,這裏我想加載:"G:\HowTomcatWorks\JavaWebServer\webroot\TestServlet.class"這個類文件,可是我將這兒的文件刪了,照樣可以運行,因爲我默認的編譯路徑是:"G:\HowTomcatWorks\JavaWebServer\bin\TestServlet.class",然後我又將這個文件也刪了,才提示找不到類文件的錯誤,真搞不懂……


------------------------------------------

再分割:很複雜,上面寫的也不一定對,後來又測試過,如果你看到了這裏,那麼也請自己測試一下,不能誤導自己呀~如有誤解,敬請指教,歡迎探討!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章