UCS只是規定如何編碼,并沒(méi)有規定如何傳輸、保存這個(gè)編碼。
例如“漢”字的UCS編碼是6C49,我可以用4個(gè)ASCII數字來(lái)傳輸、保存這個(gè)編碼;也可以用UTF-8編碼:3個(gè)連續的字節E6 B1 89來(lái)表示它。關(guān)鍵在于通信雙方都要認可。
UTF-8、UTF-7、UTF-16都是被廣泛接受的方案。UTF-8的一個(gè)特別的好處是它與ISO-8859-1完全兼容。
UTF是“UCS Transformation Format”的縮寫(xiě)。UCS可以看作是"Unicode Character Set"的縮寫(xiě)。
UTF-8就是以8位為單元對UCS進(jìn)行編碼。
---------------
內碼和"code page"
---------------
目前Windows的內核已經(jīng)支持Unicode字符集,這樣在內核上可以支持全世界所有的語(yǔ)言文字。
但是由于現有的大量程序和文檔都采用了某種特定語(yǔ)言的編碼,例如GBK,Windows不可能不支持現有的編碼,而全部改用Unicode。Windows使用代碼頁(yè)("code page")來(lái)適應各個(gè)國家和地區。"code page"可以被理解為前面提到的內碼。GBK對應的"code page"是CP936。
微軟也為GB18030定義了"code page":CP54936。但是由于GB18030有一部分4字節編碼,而Windows的代碼頁(yè)只支持單字節和雙字節編碼,所以這個(gè)"code page"是無(wú)法真正使用的。
----------------
UTF的字節序和BOM
----------------
UTF-8以字節為編碼單元,沒(méi)有字節序的問(wèn)題。
UTF-16以?xún)蓚€(gè)字節為編碼單元,在解釋一個(gè)UTF-16文本前,首先要弄清楚每個(gè)編碼單元的字節序。例如“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16字節流“594E”,那么這是“奎”還是“乙”?
Unicode規范中推薦的標記字節順序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一個(gè)有點(diǎn)小聰明的想法:在UCS編碼中有一個(gè)叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,所以不應該出現在實(shí)際傳輸中。UCS規范建議我們在傳輸字節流前,先傳輸字符"ZERO WIDTH NO-BREAK SPACE"。這樣如果接收者收到FEFF,就表明這個(gè)字節流是Big-Endian的;如果收到FFFE,就表明這個(gè)字節流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被稱(chēng)作BOM。
UTF-8不需要BOM來(lái)表明字節順序,但可以用BOM來(lái)表明編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF(讀者可以用我們前面介紹的編碼方法驗證一下)。所以如果接收者收到以EF BB BF開(kāi)頭的字節流,就知道這是UTF-8編碼了。Windows就是使用BOM來(lái)標記文本文件的編碼方式的。
--------
關(guān)于內碼
--------
內碼是指操作系統內部的字符編碼。早期操作系統的內碼是與語(yǔ)言相關(guān)的。
現在的Windows在系統內部支持Unicode,然后用代碼頁(yè)適應各種語(yǔ)言,“內碼”的概念就比較模糊了。
微軟一般將缺省代碼頁(yè)指定的編碼說(shuō)成是內碼。
內碼這個(gè)詞匯,并沒(méi)有什么官方的定義,代碼頁(yè)也只是微軟這個(gè)公司的叫法。作為程序員,我們只要知道它們是什么東西,沒(méi)有必要過(guò)多地考證這些名詞。
所謂代碼頁(yè)("code page")就是針對一種語(yǔ)言文字的字符編碼。例如GBK的"code page"是CP936,BIG5的"code page"是CP950,GB2312的"code page"是CP20936。
Windows中有缺省代碼頁(yè)的概念,即缺省用什么編碼來(lái)解釋字符。例如Windows的記事本打開(kāi)了一個(gè)文本文件,里面的內容是字節流:BA、BA、D7、D6。Windows應該去怎么解釋它呢?
是按照Unicode編碼解釋、還是按照GBK解釋、還是按照BIG5解釋?zhuān)€是按照ISO8859-1去解釋?zhuān)咳绻碐BK去解釋?zhuān)蜁?huì )得到“漢字”兩個(gè)字。按照其它編碼解釋?zhuān)赡苷也坏綄淖址?,也可能找到錯誤的字符。所謂“錯誤”是指與文本作者的本意不符,這時(shí)就產(chǎn)生了亂碼。
答案是Windows按照當前的缺省代碼頁(yè)去解釋文本文件里的字節流。缺省代碼頁(yè)可以通過(guò)控制面板的區域選項設置。記事本的另存為中有一項ANSI,其實(shí)就是按照缺省代碼頁(yè)的編碼方法保存。
Windows的內碼是Unicode,它在技術(shù)上可以同時(shí)支持多個(gè)代碼頁(yè)。只要文件能說(shuō)明自己使用什么編碼,用戶(hù)又安裝了對應的代碼頁(yè),Windows就能正確顯示,例如在HTML文件中就可以指定charset。
有的HTML文件作者,特別是英文作者,認為世界上所有人都使用英文,在文件中不指定CharSet。如果他使用了0x80-0xff之間的字符,中文Windows又按照缺省的GBK去解釋?zhuān)蜁?huì )出現亂碼。這時(shí)只要在這個(gè)html文件中加上指定CharSet的語(yǔ)句,例如:
如果原作者使用的代碼頁(yè)和ISO8859-1兼容,就不會(huì )出現亂碼了。
再說(shuō)區位碼,啊的區位碼是1601,寫(xiě)成16進(jìn)制是0x10,0x01。這和計算機廣泛使用的ASCII編碼沖突。為了兼容00-7f的ASCII編碼,我們在區位碼的高、低字節上分別加上A0。這樣“啊”的編碼就成為B0A1。我們將加過(guò)兩個(gè)A0的編碼也稱(chēng)為GB2312編碼,雖然GB2312的原文根本沒(méi)提到這一點(diǎn)。
為了識別 Unicode 文件,Microsoft 建議所有的 Unicode 文件應該以 ZERO WIDTH NOBREAK SPACE(U+FEFF)字符開(kāi)頭。這作為一個(gè)“特征符”或“字節順序標記(byte-order mark,BOM)”來(lái)識別文件中使用的編碼和字節順序。
但是,Linux/UNIX 并沒(méi)有使用 BOM,因為它會(huì )破壞現有的 ASCII 文件的語(yǔ)法約定。在 POSIX 系統中,選中的語(yǔ)言環(huán)境識別了在一個(gè)過(guò)程中的所有輸入輸出文件期望的編碼形式。
最近在做的廣告系統中,碰到了一個(gè)問(wèn)題,廣告系統采用的UTF-8編碼,而一些使用這套廣告系統的頻道頁(yè)面使用的是GB2312編碼。當然也有使用UTF-8編碼的頻道使用這套廣告系統。
頻道頁(yè)面是通過(guò)嵌入類(lèi)似如下的代碼方式,來(lái)調用廣告的。具體那個(gè)時(shí)間顯示那個(gè)廣告,或者那些廣告組合是廣告系統自己處理的。
<script type="text/javascript">< span="">script><script type="text/javascript" src="http://ads.csdn.net/AD/Show_JavaScript_AD.js" >< span="">script>
不同編碼的頁(yè)面、腳本之間互相引用,就會(huì )產(chǎn)生亂碼的問(wèn)題,解決方法就是統一成一種編碼。
asp.net 中,如果要修改輸出頁(yè)面的編碼,可以通過(guò)修改web.config中以下配置信息
<globalization requestEncoding="utf-8" responseEncoding="utf-8" />
以上只是修改整體的默認編碼,如果只有某個(gè)頁(yè)的編碼需要修改,ASP.net 中則可以簡(jiǎn)單的使用下面代碼:
Encoding gb2312 = Encoding.GetEncoding("gb2312");Response.ContentEncoding = gb2312;
在非ASP.net 應用中,可能你讀到的數據是UTF-8編碼,但是你要轉換為GB2312編碼,則可以參考以下代碼:
string utfinfo = "document.write(\"alert(‘aa你好么??‘);\");";string gb2312info = string.Empty;Encoding utf8 = Encoding.UTF8;Encoding gb2312 = Encoding.GetEncoding("gb2312");// Convert the string into a byte[].byte[] unicodeBytes = utf8.GetBytes(utfinfo);// Perform the conversion from one encoding to the other.byte[] asciiBytes = Encoding.Convert(utf8, gb2312, unicodeBytes);// Convert the new byte[] into a char[] and then into a string.// This is a slightly different approach to converting to illustrate// the use of GetCharCount/GetChars.char[] asciiChars = new char[gb2312.GetCharCount(asciiBytes, 0, asciiBytes.Length)];gb2312.GetChars(asciiBytes, 0, asciiBytes.Length, asciiChars, 0);gb2312info = new string(asciiChars);
當然,其他各種編碼之間的轉換,跟上述代碼也類(lèi)似的,就不描述了。
有一個(gè)Web項目,Web.Config中requestEncoding和responseEncoding都是gb2312,而從數據庫中取出的簡(jiǎn)介數據可能是中文和韓、日文混合的內容,這時(shí)候如果直接輸出到頁(yè)面上,其頁(yè)面會(huì )出現亂碼,其中的韓文內容無(wú)法正確顯示。當然如果項目的編碼都使用Utf-8的話(huà)將沒(méi)有這個(gè)問(wèn)題,但這個(gè)項目是一個(gè)老項目,為了盡量不要影響已有的程序,所以無(wú)法將編碼改為Utf-8,只能在本頁(yè)面上動(dòng)腦筋。
經(jīng)過(guò)研究,發(fā)現這個(gè)問(wèn)題可以通過(guò)Html實(shí)體的方法解決。
對于Html實(shí)體請參考:
Character entity references in HTML 4
測試代碼:
Byte[] bComments = Encoding.UTF8.GetBytes("一ンブル????中文");
char[] cComments = Encoding.UTF8.GetChars(bComments);
StringBuilder charBuilder = new StringBuilder();
foreach(char c in cComments)
{
if(c > ‘\u0800‘)
{
charBuilder.Append("&#");
charBuilder.Append((int)c);
}
else
{
charBuilder.Append(c);
}
}
Response.Write(charBuilder.ToString());
這段代碼的作用是將所有的中文、韓文、日文字符通過(guò)硬編碼輸出成為html實(shí)體。而Html實(shí)體是不受ResponseEncoding和頁(yè)面編碼集影響的。
說(shuō)明:
\u0800 以上的為中、韓、日字符。
中文的范圍:\u4e00 - \u9fa5,日文在\u0800 - \u4e00,韓文為\u9fa5以上。
這個(gè)方法僅僅是為了解決小范圍問(wèn)題,如果各位有更好的辦法請指教。
ms的Best Practices Analyzer Tool for Microsoft SQL Server 2000 1.0上個(gè)月發(fā)布了1.0版本,和beta版相比,看起來(lái)沒(méi)有什么太大的變化。Best Practices Analyzer Tool for Microsoft SQL Server 2000檢查的一些rules可以做為t-sql編程的checklist
sql server數據庫編程指導以及最佳實(shí)踐
原則
編寫(xiě)高可讀的代碼:遵循命名原則和代碼風(fēng)格約定
開(kāi)始就要關(guān)注t-sql代碼性能的影響:減少網(wǎng)絡(luò )流量,減少磁盤(pán)IO,利用索引,避免lock
編寫(xiě)安全的代碼
------------------------------------------------------------------------------
命名數據庫對象時(shí),采用統一的前綴或者后綴
采用統一的前綴或者后綴是為了提高代碼的可讀性,但是
存儲過(guò)程不要使用sp_作為前綴,函數不要使用fn_作為前綴。
如果sql server發(fā)現存儲過(guò)程以sp_作為前綴,都會(huì )先到master數據庫中查詢(xún)這個(gè)存儲過(guò)程
添加必要的注釋
存儲過(guò)程或者函數,視圖前應該注釋創(chuàng )建者, 創(chuàng )建時(shí)間,修改者,修改時(shí)間,功能注釋?zhuān)褂谜f(shuō)明,同時(shí)包含一到多條執行該對象的語(yǔ)句
及時(shí)檢查執行狀況
默認情況下,如果一條sql語(yǔ)句執行錯誤,sql server不會(huì )自動(dòng)roll back前面的執行(可以設置:SET XACT_ABORT ON),sql語(yǔ)句執行完畢后,需要及時(shí)通過(guò)全局變量@@error和@@rowcount來(lái)檢查執行狀況。
用標準的join方式
標準的join方式是指while語(yǔ)句中只包含過(guò)濾條件,不包含join條件
盡量避免客戶(hù)端程序直接通過(guò)select,insert,update等直接操作數據庫
用存儲過(guò)程封裝數據訪(fǎng)問(wèn),存儲過(guò)程是經(jīng)過(guò)編譯的,不用每次計算execute plan。而且封裝了邏輯,同時(shí)增加了安全性。
存儲過(guò)程如果需要返回數據,使用output關(guān)鍵字
不要用return返回數據,存儲過(guò)程的return應該返回存儲過(guò)程的執行狀況,如果需要返回數據,使用帶有output關(guān)鍵字的參數
謹慎使用IDENTITY作為表的主鍵的數據類(lèi)型
IDENTITY會(huì )給客戶(hù)端程序和database交互帶來(lái)很多影響,而且在數據導入導出時(shí)也會(huì )帶來(lái)麻煩,需要仔細評估這些影響。但是IDENTITY和guid相比也有優(yōu)點(diǎn),就是可讀性。
盡量避免使用NULL
如果沒(méi)有特別設置,null參與的運算結果都為null,如果疏忽這一原則,會(huì )對程序邏輯的正確性帶來(lái)影響,而且,客戶(hù)端程序需要額外的步驟來(lái)處理NULL。需要設置ANSI_NULLS為ON。
在insert語(yǔ)句中,使用確定的列名
insert語(yǔ)句中,使用確定的列名以間少表結構變化對t-sql代碼帶來(lái)的影響
盡量使用外鍵,約束檢查來(lái)保證數據的完整性
數據完整性至關(guān)重要,外鍵,約束檢查可以避免另外寫(xiě)代碼來(lái)保證數據完整性
不要在查詢(xún)時(shí)用select * ,用確定的列名來(lái)代替 *
查詢(xún)結果中冗余的信息影響整體的性能
盡量避免使用服務(wù)器端游標
服務(wù)器端游標對性能有嚴重的影響,應當盡量避免,比如可以用while循環(huán)來(lái)代替游標,如果不能避免,則應選擇最合適的游標類(lèi)型
盡量避免使用臨時(shí)表
臨時(shí)表會(huì )發(fā)生磁盤(pán)IO操作,影響性能,可以用嵌套查詢(xún),view,或者table變量來(lái)代替臨時(shí)表。如果需要緩存大量的數據,臨時(shí)表優(yōu)于table變量,同時(shí)注意為臨時(shí)表建index
如果需要執行一系列sql命令,在前面添加SET NOCOUNT ON
執行SET NOCOUNT ON,sql命令執行影響的行數不會(huì )傳回客戶(hù)端,減少網(wǎng)絡(luò )流量,提高性能
在字符串匹配查詢(xún)時(shí),避免在第一個(gè)字符位置使用通配符
如果第一個(gè)字符位置使用通配符,則index不起作用
避免使用IN 或者NOT IN
使用IN 或者NOT IN,則index不起作用
事務(wù)處理時(shí),盡可能的占用最少的資源
事務(wù)處理時(shí),盡可能的占用最少的資源以減少資源的鎖定,提高數據庫整體性能。同時(shí)檢查加鎖類(lèi)型,盡量使用低級別的加鎖類(lèi)型。
匹配的事務(wù)處理
如果存儲過(guò)程開(kāi)始了事務(wù)處理,應該負責結束這個(gè)事物處理,submit或者rollback
操作NCHAR或者NVARCHAR數據類(lèi)型的列時(shí),使用N關(guān)鍵字
使用N關(guān)鍵字,sql server會(huì )使用unicode編碼,避免出現亂碼
盡量避免使用TEXT,NTEXT,binary,image數據類(lèi)型的字段,盡量避免將文件或者圖片直接存入數據庫
這些數據類(lèi)型訪(fǎng)問(wèn)方式不同于普通的數據類(lèi)型。數據庫也不是存儲文件或者圖片內容合適的地方
盡量使用VARCHAR代替CHAR,用NVARCHAR代替VARCHAR,
用VARCHAR代替CHAR是為了節省數據庫空間,NVARCHAR代替VARCHAR是為了避免unicode帶來(lái)的麻煩
如果某個(gè)table中的數據對不同用戶(hù)的可見(jiàn)性是不一樣的,使用view來(lái)隔離用戶(hù)對table的直接訪(fǎng)問(wèn)
檢查sql注入式攻擊對代碼的影響。
聯(lián)系客服