Java Web程式設計
一.Servlet
1.RequestDispatcher
RequestDispatcher是一個介面,它包含兩個方法:forward(request, response)和
include(request, response)。RequestDispatcher 有一個特點,就是瀏覽器上顯示
的URL是最先請求的目標資源的URL,不會因為使用了forward、include方法而改
變。因此forward和include的呼叫對於使用者來說是透明的。
(1)forward
這個方法將請求從一個 Servlet or JSP目標資源 上 轉發到伺服器上的另一個
資源(servlet、JSP 檔案或 HTML 檔案,這些資源必須是當前Web上下文中
的),讓其它的資源去生成響應資料。如下圖中的,使用者請求的是目標資源
servlet1,servlet1接受到請求後,轉發到servlet2,真正產生響應資料是
servlet2,而servlet1只是起個引導轉發作用。瀏覽器的位址列不會變,依然
是servlet1的URL。
注意點:
(a)在目標資源中呼叫forward方法時,必須保證此響應沒有提交。也就是不
要使用 ServletResponse 物件的輸出流物件,因為即便你寫入了資料到
響應緩衝區,最後也會被清空,如果緩衝區資料被重新整理提交(out.flush),
還會丟擲IllegalStateException異常。
(b)對於forward方法傳遞的request物件:雖然我們從呼叫上看,好像是將
request物件傳遞給轉動的資源上去了,但是我發現目標資源使用的
request物件和轉發的資源使用的request物件不是同一個request物件,
因為分別從這2個request中獲取RequestURL,發現是不一樣的。但是
在目標資源request提取的Paramter 和 Attribute ,在轉發後的資源的
request物件中,依然都可以提取到,且是相同的。所以,二者只是在
請求路徑相關的屬性上不同,其它API呼叫返回的都是一樣的。
(c)在forward語句的前後,都不應該有響應輸出的語句,應該會被忽略。
ServletRequest介面的getRequestDispatcher()方法返回
RequestDispatcher的物件。句法:
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/sessionLoginDemo/login.jsp");//得到轉發器
requestDispatcher.forward(request, response);//轉發(排程)請求給/sessionLoginDemo/login.jsp 並由login.jsp傳送response給客戶端。
(2)include
此方法用於包含響應中某個資源(servlet、JSP 頁面和 HTML 檔案)的內
容。呼叫者指定一個被包含的資源,將這個包含的資源(JSP,Servlet,
HTML)的響應資料包含到自己的響應體中。被包含的資料是在伺服器上經
過執行產生的,因此是動態包含,而不同於JSP中的include指令,它是
JSP轉譯期的靜態包含。這個過程實質是用一個相同的Request再請求
一次被包含的資源,將被包含的資源的響應資料包含到原本的資源中去,
構成它的響應資料的一部分。
2.response.sendRedirect
示例:response.sendRedirect("login.jsp");
使用response.sendRedirect傳遞引數:
response.sendRedirect("/UsersManager/MainFrame?uname="+username+"&pwd="+password);
3.RequestDispatcher.forward和response.sendRedirect的區別:
(1)response.sendRedirect相當於瀏覽器接收到了響應之後又向伺服器傳送
了一次請求,所以相當於兩次請求。RequestDispatcher.forward相當於
方法呼叫,在執行當前檔案的過程中轉向執行目標檔案,兩個檔案(當
前檔案和目標檔案)屬於同一次請求,最本質的特點就是兩次請求共享
了reques物件和response物件。
(2)位址列不同:response.sendRedirect方式下使用者在瀏覽器位址列中看
到的是目標檔案的地址,RequestDispatcher.forward方式下使用者在瀏覽
器位址列中看到的是當前檔案的地址。
4.java web的四大作用域
(1)PageContext域:作用範圍是整個JSP頁面,是四大作用域中最小的一
個;生命週期是當對JSP的請求時開始,當響應結束
時銷燬。
(2)ServletRequest域:作用範圍是整個請求鏈(請求轉發也存在);生命
週期是在service方法呼叫前由伺服器建立,傳入
service方法。整個請求結束,request生命結束。
執行緒安全
(3)HttpSession域:作用範圍是一次會話。生命週期是在第一次呼叫
request.getSession()方法時,伺服器會檢查是否已經
有對應的session,如果沒有就在記憶體中建立一個
session並返回。當一段時間內session沒有被使用
(預設為30分鐘),則伺服器會銷燬該session。如果
伺服器非正常關閉(強行關閉),沒有到期的session
也會跟著銷燬。如果呼叫session提供的invalidate(),
可以立即銷燬session。執行緒不安全
session銷燬的方式:
(a)超時(一般伺服器設定超時時間為30分鐘)伺服器會銷燬
session;
(b)點選控制檯的紅色按鈕異常關閉伺服器要銷燬session
(c)手動呼叫session的invalidate方法session.invalidate();
注意:伺服器正常關閉不銷燬session,()session會存到我
們的硬碟中,也就是我們正常的點選stop server()會在
tomcat的work的Catalina\localhost\專案名稱下面生成
一個檔案SESSIONS(執行序列化),當伺服器再次啟動
的時候會載入此檔案(反序列化),倘若沒有實現序列化
介面(Serializable)可能會報錯因為序列化和反序列化會
依據一個id。
問:瀏覽器關閉後session會銷燬嗎?
答:不會。
我們知道Session是存在於伺服器端的,當把瀏覽器關閉
時,瀏覽器並沒有向伺服器傳送任何請求來關閉Session,
自然Session也不會被銷燬,但是可以做一點努力,在所
有的客戶端頁面裡使用js的window.onclose來監視瀏覽器
的關閉動作,然後向伺服器傳送一個請求來關閉Session,
但是這種做法在實際的開發中也是不推薦使用的,最正常
的辦法。
問:那麼為什麼當我們關閉瀏覽器後,就再也訪問不到之前的
session了呢?
答:其實之前的Session一直都在伺服器端,而當我們關閉瀏
覽器時,此時的Cookie是存在於瀏覽器的程序中的,當瀏
覽器關閉時,Cookie也就不存在了。其實Cookie有兩種:
一種是存在於瀏覽器的程序中;一種是存在於硬碟上。而
session的Cookie是存在於瀏覽器的程序中,那麼這種
Cookie我們稱為會話Cookie,當我們重新開啟瀏覽器視窗
時,之前的Cookie中存放的Sessionid已經不存在了,此時
伺服器從HttpServletRequest物件中沒有檢查到sessionid,
伺服器會再發送一個新的存有Sessionid的Cookie到客戶端
的瀏覽器中,此時對應的是一個新的會話,而伺服器上原先
的session等到它的預設時間到之後,便會自動銷燬。就是
不去管它,讓它等到預設的時間後,自動銷燬。
注:當在同一個瀏覽器中同時開啟多個標籤,傳送同一個請
求或不同的請求,仍是同一個session;當不在同一個視窗
中開啟相同的瀏覽器時,傳送請求,仍是同一個session;
當使用不同的瀏覽器時,傳送請求,即使傳送相同的請
求,是不同的session;當把當前某個瀏覽器的視窗全關閉,
再開啟,發起相同的請求時,就是本文所闡述的,是不同
的session,但是它和session的生命週期是沒有關係的。
(4)ServletContext(application)域:作用範圍是整個Web應用。當Web應用
被載入進容器時建立代表整個web應用
的ServletContext物件,當伺服器關閉或
Web應用被移除時,ServletContext物件
跟著銷燬。執行緒不安全
關於作用域的執行緒安全的詳細內容,檢視:
http://www.itkeyword.com/doc/903165062469129x507/Web-ServletContex-SessionRequest
6.web應用中的物件
(1)Servlet
Servlet通常稱為伺服器端小程式,是執行在伺服器端的程式,用於處理及響
應客戶的請求。Servlet是個特殊的java類,繼承於HttpServlet。客戶端通常
只有GET和POST兩種請求方式,Servlet為了響應則兩種請求,必須重寫
doGet()和doPost()方法。大部分時候,Servlet對於所有的請求響應都是完全
一樣的,此時只需要重寫service()方法即可響應客戶端的所有請求。
(a)HttpServlet有三個方法:
init(ServletConfig config):建立Servlet例項時,呼叫該方法的初始化
Servlet資源。在 Servlet 的生命期中,僅
執行一次 init()方法。它是在伺服器裝入
Servlet 時執行的。可以對它進行覆蓋。
service() 方法:service() 方法是 Servlet 的核心。每當一個客戶請求一
個HttpServlet物件,該物件的service() 方法就要被呼叫,
而且傳遞給這個方法一個"請求"(ServletRequest)物件和
一個"響應"(ServletResponse)物件作為引數。 在
HttpServlet中已存在service() 方法。預設的服務功能是
呼叫與 HTTP 請求的方法相應的 do 功能。例如, 如果
HTTP 請求方法為 GET,則預設情況下呼叫 doGet() ;
HTTP請求方法為POST,則預設情況下呼叫doPost()。
Servlet 應該為 Servlet 支援的 HTTP方法覆蓋 do 功能。
因為 HttpServlet.service() 方法會檢查請求方法是否呼叫
了適當的處理方法,不必要覆蓋 service() 方法。只需覆
蓋相應的 do 方法就可以了。
destroy() 方法:destroy() 方法僅執行一次,即在伺服器停止且卸裝
Servlet時執行該方法。典型的,將 Servlet 作為伺服器
程序的一部分來關閉。可以對它進行覆蓋。
(b)Servlet的響應
Servlet的響應可以是下列幾種型別:
一個輸出流,瀏覽器根據它的內容型別(如text/HTML)進行解釋。
一個HTTP錯誤響應, 重定向到另一個URL、servlet、JSP。
(c)Servlet的生命週期
(i)建立Servlet例項。
建立Servlet例項有兩個時機:
第一個時機:客戶端第一次請求某個Servlet時,系統建立該
Servlet的例項。
第二個時機:Web應用啟動時立即建立Servlet例項,即
load-on-start Servlet。
load-on-start:
load-on-startup標記容器是否在啟動的時候例項化並呼叫其
init()方法的優先順序。它的值表示 servlet應該被載入的順序。
當值為0或者大於0時,表示容器在應用啟動時就載入並初始
化這個servlet。如果值小於0或未指定時,則表示只有在第一
次請求的容器才在該servlet呼叫初始化函式。正值越小
servlet的優先順序越高,應用啟動時就越先載入。值相同時,
容器就會自己選擇順序來載入。
(ii)Web容器呼叫Servlet的init()方法,對Servlet進行初始化。
(iii)Servlet初始化後,將一直存在於容器中,用於響應客戶端請求,如
果客戶端傳送GET請求,容器呼叫Servlet的doGet()方法處理並響應
請求;如果客戶端傳送POST請求,容器呼叫Servlet的doPost()方法
處理並響應請求。或者統一使用service()方法處理來響應使用者請求。
(iv)Web容器決定銷燬Servlet時,先呼叫Servlet的destory()方法,通常
在關閉Web應用時銷燬Servlet例項。
(d)Servlet的執行緒安全
(i)物件分為有狀態的物件和無狀態的物件
有狀態的物件:有資料儲存功能,即有例項變數;
無狀態的物件:無資料儲存功能,即無例項變數。
Servlet是一個單例模式,是否執行緒安全即取決於它的實現是有狀態的
Servlet還是無狀態的Servlet。傳統的實現方式,即實現HttpServlet為
有狀態的Servlet,所以非執行緒安全,它的執行緒安全問題如下:
靜態變數:非執行緒安全
例項變數:非執行緒安全
區域性變數:執行緒安全
如果Servlet是實現SingleThreadModel介面,它就是無狀態的,即線
程安全。
(1)ServletContext(application)
官方叫servlet上下文,ServletContext是一個web應用的上下文,伺服器會為
每一個工程建立一個物件,這個物件就是ServletContext物件。這個物件全域性
唯一,而且工程內部的所有servlet都共享這個物件。所以叫全域性應用程式共
享物件。它是一個全域性資訊的儲存空間,代表當前web應用。
(a)建立和銷燬
ServletContext在web應用(伺服器)啟動時建立,ServletContext在Web
應用(伺服器)關閉時釋放。
(b)如何獲取ServletContext
(i)呼叫ServletConfig類的getServletContext()方法
在init(ServletConfig config)方法中,使用
ServletContext context=config.getServletContext();
(ii)呼叫GenericServlet類的getServletContext()方法
其實這種方式也是呼叫ServletConfig類的getServletContext()方法,
因為GenericServlet類實現了ServletConfig介面;
(iii)呼叫HttpSession類的getServletContext()方法
(iv)ServletContextEvent類只有一個方法,就是getServletContext()
(2)ServletContextListener和ServletContextEvent
當Servlet 容器啟動或終止Web 應用時,會觸發ServletContextEvent 事件,該
事件由ServletContextListener 來處理。在 ServletContextListener 介面中定義
了處理ServletContextEvent 事件的兩個方法。
/**
* 當Servlet 容器啟動Web 應用時呼叫該方法。在呼叫完該方法之後,容器再對Filter 初始化,
* 並且對那些在Web 應用啟動時就需要被初始化的Servlet 進行初始化。
*/
contextInitialized(ServletContextEvent sce)
/**
* 當Servlet 容器終止Web 應用時呼叫該方法。在呼叫該方法之前,容器會先銷燬所有的Servlet 和Filter 過濾器。
*/
contextDestroyed(ServletContextEvent sce)
下面展示三個例子:
例一,在服務啟動時,將資料庫中的資料載入進記憶體,並將其賦值給一個屬性
名,其它的 Servlet 就可以通過 getAttribute 進行屬性值的訪問。包括兩
個步驟:
(i)實現 servletContextListerner 介面 並將要共享的通過
setAttribute ( name,data )方法提交到記憶體中去;
(ii)應用專案通過 getAttribute(name) 將資料取到 。
Java程式碼:
public class ServletContextLTest implements ServletContextListener{
// 實現其中的銷燬函式
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("this is last destroyeed");
}
// 實現其中的初始化函式,當有事件發生時即觸發
public void contextInitialized(ServletContextEvent sce) {
ServletContext sct=sce.getServletContext();
Map<Integer,String> depts=new HashMap<Integer,String>();
Connection connection=null;
PreparedStatement pstm=null;
ResultSet rs=null;
try{
connection=ConnectTool.getConnection();
String sql="select deptNo,dname from dept";
pstm=connection.prepareStatement(sql);
rs=pstm.executeQuery();
while(rs.next()){
depts.put(rs.getInt(1), rs.getString(2));
}
// 將所取到的值存放到一個屬性鍵值對中
sct.setAttribute("dept", depts);
System.out.println("======listener test is beginning=========");
}catch(Exception e){
e.printStackTrace();
}finally{
ConnectTool.releasersc(rs, pstm, connection);
}
}
}
在完成上述編碼後,仍需在 web.xml 中進行如下配置,以使得該監聽器可以起作用。
web.xml程式碼:
<listener>
<listener-class>ServletContextTest.ServletContextLTest</listener-class>
</listener>
在完成上述配置後, web 伺服器在啟動時,會直接載入該監聽器,通過以下的應用
程式就可以進行資料的訪問。
例二,啟動執行緒
public class DSAction extends Thread implements ServletContextListener {
public void contextInitialized(ServletContextEvent arg0) {
super.start();// 啟動一個執行緒
}
public void zdfs() throws IOException {
Huoquzhuye u = new Huoquzhuye();// 爬蟲方法類
Htmlneirong h = new Htmlneirong();// 存入資料庫類
List<String> list = u.seturl("http://xxxxxxx");
for (int i = 0; i < list.size(); i++) {
String txt = list.get(i).substring(0, 22);
String start = list.get(i).substring(4, 14);
String end = list.get(i).substring(22, list.get(i).length());
try {
h.seturl(txt, start, end);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
@Override
public void run() {
while (true) {
try {
this.zdfs();
super.sleep(1000 * 60 * 10);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/*
* (non-Javadoc)
*
* @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.
* ServletContextEvent)
*/
/*
* (non-Javadoc)
*
* @see
* javax.servlet.ServletContextListener#contextInitialized(javax.servlet
* .ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent arg0) {
super.stop();// 停止執行緒
}
}
web.xml程式碼
<listener>
<listener-class>bj.hbj.dingshi.DSAction</listener-class>
</listener>
(i)呼叫super.start()開啟執行緒。
(ii)最後關閉執行緒super.stop()。
7.web.xml
(1)web.xml的載入順序:
ServletContext -> context-param(無順序)-> listener(無順序)-> filter(書寫順序)
-> servlet(load-on-startup優先順序)
詳細步驟如下:
(i)啟動一個web專案,web容器(如tomcat)讀取web.xml檔案,讀取其中的配置信
息。
(ii)容器建立一個servlet上下文(servletContext),這個web專案所有部分共享這個
上下文。
(iii)容器將<context-param>轉換為鍵值對,交給servletContext
(iv)容器建立<listener>中的監聽器例項
(v)觸發contextInitialized方法,listener被呼叫(當Servlet 容器啟動或終止Web 應
用時,會觸發ServletContextEvent 事件,該事件由ServletContextListener 來
處理。在 ServletContextListener 介面中定義了處理ServletContextEvent 事件
的兩個方法contextInitialized和contextDestroyed,web.xml有
contextLoaderListener監聽器,spring等框架實現了本監聽器的介面方法)調
用完contextInitialized方法後,容器再對filter初始化。
ContextLoaderListener:Spring實現的類,它繼承自ContextLoader,並且實
現ServletContextListener介面(實現了
contextInitialized和contextDestroyed,這是它的核
心功能)。詳細檢視:
https://blog.csdn.net/qq_15037231/article/details/78743765
(vi)容器對web.xml中的指定load-on-startup的值為正數Servlet初始化
(優先順序1,2,3...->遞減),負數或不指定則在該Servlet呼叫時初始化
(springMVC的初始化為此階段)
(2)web.xml檔案中配置<context-param>和<init-param>的區別
<context-param>和<init-param>都是上下文引數,但它們的範圍和使用方式不同。
<context-param>是application範圍內的初始化引數,用於向servlet-context提供鍵
值對,即應用程式的上下文資訊,listener、filter等初始化時會用到這些資訊。
<init-param>是servlet範圍內的引數,只能在servlet類的init()方法中取得。
示例如下:
<context-param>
<param-name>context/param</param-name>
<param-value>avalible during application</param-value>
</context-param>
<servlet>
<servlet-name>ReadContext</servlet-name>
<servlet-class>file.ReadContext</servlet-class>
<init-param>
<param-name>user1</param-name>
<param-value>user1-ps</param-value>
</init-param>
</servlet>
(3)<session-config></session-config>
<session-config> 用於設定容器的session引數,比如:<session-timeout> 用於指
定http session的失效時間,-1 代表session永遠不會過期。
(4)<listener></listener>
(a)listener介紹
<listener>為web應用程式定義監聽器,監聽器用來監聽各種事件,比如:
application和session事件,所有的監聽器按照相同的方式定義,功能取決去
它們各自實現的介面,常用的Web事件介面有如下幾個:
(i)ServletContextListener:用於監聽Web應用的啟動和關閉;
(ii)ServletContextAttributeListener:用於監聽ServletContext範圍
(application)內屬性的改變;
(iii)ServletRequestListener:用於監聽使用者的請求;
(iv)ServletRequestAttributeListener:用於監聽ServletRequest範圍
(request)內屬性的改變;
(v)HttpSessionListener:用於監聽使用者session的開始和結束;
(vi)HttpSessionAttributeListener:用於監聽HttpSession範圍(session)
內屬性的改變。
<listener>主要用於監聽Web應用事件,其中有兩個比較重要的WEB應用
事件:應用的啟動和停止(starting up or shutting down)和Session的創
建和失效(created or destroyed)。應用啟動事件發生在應用第一次被
Servlet容器裝載和啟動的時候;停止事件發生在Web應用停止的時候。
Session建立事件發生在每次一個新的session建立的時候,類似地
Session失效事件發生在每次一個Session失效的時候。為了使用這些
Web應用事件做些有用的事情,我們必須建立和使用一些特殊的“監聽
類”。它們是實現了以下兩個介面中任何一個介面的簡單java類:
javax.servlet.ServletContextListener或
javax.servlet.http.HttpSessionListener,如果想讓你的類監聽應用的啟動
和停止事件,你就得實現ServletContextListener介面;想讓你的類去監
聽Session的建立和失效事件,那你就得實現HttpSessionListener介面。
(b)Listener配置
配置Listener只要向Web應用註冊Listener實現類即可,無序配置引數之
類的東西,因為Listener獲取的是Web應用ServletContext(application)
的配置引數。為Web應用配置Listener的兩種方式:
(i)使用@WebListener修飾Listener實現類即可。
(ii)在web.xml文件中使用<listener>進行配置。
注意:6中的(2)是隻針對ServletContextEvent配置的一個Listener。
web.xml的方式如下所示:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
(5)<filter></filter>
二.Jsp
1.Forward和Redirect
Forward和Redirect代表了兩種請求轉發方式:直接轉發和間接轉發。
直接轉發方式(Forward):客戶端和瀏覽器只發出一次請求,Servlet、
HTML、JSP或其它資訊資源,由第二個資訊資
源響應該請求,在請求物件request中,儲存的
物件對於每個資訊資源是共享的。
間接轉發方式(Redirect):實際是兩次HTTP請求,伺服器端在響應第一
次請求的時候,讓瀏覽器再向另外一個URL發
出請求,從而達到轉發的目的。
2.Jsp的九個隱藏變數
(1)Request
(2)Response
(3)Session
(4)application
(5)out
(6)config
javax.servlet.ServletConfig例項化物件,我們也可以在web.xml檔案中配置
JSP,只是很少用。
(7)page
翻譯成Servlet後相當於this
(8)PageContext
參看:http://www.cnblogs.com/fjdingsd/p/5117303.html
(9)exception
exception 物件的作用是顯示異常資訊,只有在包含 isErrorPage="true" 的頁
面中才可以被使用,在一般的JSP頁面中使用該物件將無法編譯JSP檔案。
excepation物件和Java的所有物件一樣,都具有系統提供的繼承結構。
exception 物件幾乎定義了所有異常情況。在Java程式中,可以使用try/catch
關鍵字來處理異常情況; 如果在JSP頁面中出現沒有捕獲到的異常,就會生
成 exception 物件,並把 exception 物件傳送到在page指令中設定的錯誤頁
面中,然後在錯誤頁面中處理相應的 exception 物件。
3.<%@include%>和<jsp:include>的區別
<%@include file="檔案的URL"%> **靜態引入**
頁面請求之前預編譯,所有程式碼包含進來之後,一起進行處理,把所有程式碼合在
一起,編譯成一個servlet
<jsp:include page="檔案的URL"/>**動態引入**
所有程式碼分別處理,在頁面被請求的時候才編譯,被編譯成多個servlet,頁面語
法相對獨立,處理完成之後再將程式碼的顯示結果(處理結果)組合進來。
三.Web應用的編碼問題
1.先了解字符集和編碼
(1)字符集和編碼
概念:簡單的說字符集就規定了某個文字對應的二進位制數字存放方式
(編碼)和某串二進位制數值代表了哪個文字(解 碼)的轉換關係
我們在計算機螢幕上看到的是實體化的文字,而在計算機儲存介質中存放的
實際是二進位制的位元流。那 麼在這兩者之間的轉換規則就需要一個統一的標
準,否則把我們的U盤插到老闆的電腦上,文件就亂碼了;小夥伴QQ上傳過
來的檔案,在我們本地開啟又亂碼了。 於是為了實現轉換標準,各種字符集
標準就出現了。
例如,“屌”這個字,對應的編碼如下:
字符集 | 16進位制編碼 | 對應的二進位制資料 |
---|---|---|
UTF-8 | 0xE5B18C | 1110 0101 1011 0001 1000 1100 |
UTF-16 | 0x5C4C | 1011 1000 1001 1000 |
GBK | 0x8CC5 | 1000 1100 1100 0101 |
(a)ASCII
ASCII 碼使用指定的 7 位或 8 位二進位制數組合來表示 128 或 256 種可能
的字元。標準 ASCII 碼也叫基礎ASCII碼,使用 7 位二進位制數來表示所有
的大寫和小寫字母,數字 0 到 9、標點符號, 以及在美式英語中使用的
特殊控制字元。
(b)非ASCII編碼
英語用128個符號編碼就夠了,但是用來表示其他語言,128個符號是不夠
的。比如,在法語中,字母上方有注音符號,它就無法用 ASCII 碼錶示。
於是,一些歐洲國家就決定,利用位元組中閒置的最高位編入新的符號。比
如,法語中的é的編碼為130(二進位制10000010)。這樣一來,這些歐洲
國家使用的編碼體系,可以表示最多256個符號。但是,這裡又出現了新
的問題。不同的國家有不同的字母,因此,哪怕它們都使用256個符號的
編碼方式,代表的字母卻不一樣。比如,130在法語編碼中代表了é,在希
伯來語編碼中卻代表了字母Gimel (ג),在俄語編碼中又會代表另一個符號。
但是不管怎樣,所有這些編碼方式中,0--127表示的符號是一樣的,不一
樣的只是128--255的這一段。至於亞洲國家的文字,使用的符號就更多了,
漢字就多達10萬左右。一個位元組只能表示256種符號,肯定是不夠的,就必
須使用多個位元組表達一個符號。比如,簡體中文常見的編碼方式是GB2312,
使用兩個位元組表示一個漢字,所以理論上最多可以表示 256 x 256 = 65536
個符號。
(c)UNICODE
正如上一節所說,世界上存在著多種編碼方式,同一個二進位制數字可以被
解釋成不同的符號。因此,要想開啟一個文字檔案,就必須知道它的編碼
方式,否則用錯誤的編碼方式解讀,就會出現亂碼。為什麼電子郵件常常
出現亂碼?就是因為發信人和收信人使用的編碼方式不一樣。以想象,如
果有一種編碼,將世界上所有的符號都納入其中。每一個符號都給予一個
獨一無二的編碼,那麼亂碼問題就會消失。這就是 Unicode,就像它的名
字都表示的,這是一種所有符號的編碼。Unicode 當然是一個很大的集合,
現在的規模可以容納100多萬個符號。每個符號的編碼都不一樣,比如,
U+0639表示阿拉伯字母Ain,U+0041表示英語的大寫字母A,U+4E25表
示漢字嚴。具體的符號對應表,可以查詢unicode.org,或者專門的漢字對
&nbs