成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

漫談.NET開(kāi)發(fā)中的字符串編碼

開(kāi)發(fā) 后端
本文將向讀者介紹將字符串對(duì)象的序列化,編碼方面的問(wèn)題希望能引起大家的重視,以更方便把它們保存到文件流(FileStream)中。

說(shuō)明:

在《.NET 4.0面向?qū)ο缶幊搪劇坊A(chǔ)篇《13.2.1 序列化與流》中,向大家介紹了如何向流中序列化一個(gè)對(duì)象。

本篇擴(kuò)充閱讀將向讀者介紹將字符串對(duì)象的序列化,這里面的關(guān)鍵是字符串應(yīng)該如何編碼和解碼為二進(jìn)制數(shù)值,從而可以把它們保存到文件流(FileStream)中,或者通過(guò)網(wǎng)絡(luò)流(NetworkStream)將它們遠(yuǎn)程發(fā)送到另一臺(tái)計(jì)算機(jī)上。

1 引子

在實(shí)際開(kāi)發(fā)中,經(jīng)常需要將一些字符串寫(xiě)入到文本文件中,或者從文本文件中讀入字符串,在.NET應(yīng)用程序中,通常使用StreamReader或StreamWriter兩個(gè)類(lèi)完成這一工作,比如以下代碼將fileContent字串寫(xiě)入到FileName文件中:

  1. static void WriteFileUseStreamWriter(String fileContent, String FileName)  
  2. {  
  3.   using (StreamWriter writer = new StreamWriter(FileName))  
  4.   {  
  5.     writer.Write(fileContent);  
  6.   }  

如果你使用.NET基類(lèi)庫(kù)中相關(guān)類(lèi)(比如StreamReader或下面用到的File類(lèi))去讀取這個(gè)文件,你會(huì)發(fā)現(xiàn)一切如你所愿地正常運(yùn)轉(zhuǎn):

  1. WriteFileUseStreamWriter("中國(guó)ab""test.txt");  
  2. Console.WriteLine(File.ReadAllText("test.txt"));  //輸出:“中國(guó)ab”  

由于多數(shù)情況下我們都工作在中文Windows下,而且往往都是某個(gè).NET程序?qū)懀硪粋€(gè).NET程序讀,所以,不少.NET程序員可能都沒(méi)注意到這其中其實(shí)存在著一個(gè)字符編碼的問(wèn)題,在特定的場(chǎng)合下,這一問(wèn)題會(huì)給我們帶來(lái)麻煩。

請(qǐng)看圖1:

圖 1 記事本支持的編碼方式

默認(rèn)情況下,Windows記事本以ANSI編碼方式保存文件。如圖1所示,如果文本內(nèi)容為“中國(guó)ab”,記事本將其以ASNI方式保存為“test.txt”,則以下代碼將“罷工”了(參看圖2):

  1. Console.WriteLine(File.ReadAllText("test.txt")); 

圖 2 漢字將顯示為亂碼

如圖 2所示,F(xiàn)ile.ReadAllText方法打開(kāi)“test.txt”文件時(shí),會(huì)發(fā)現(xiàn)英文字符可以正常顯示,但中文將顯示為亂碼。

2 了解字符的編碼

我們可以做個(gè)試驗(yàn),使用記事本將“中國(guó)ab”這個(gè)中英混雜的字符串以不同編碼方式保存為多個(gè)“.txt”文件,然后直接查看其二進(jìn)制內(nèi)容

圖 3  比對(duì)字符編碼

圖 3展示了“中國(guó)ab”按四種編碼方式(ANSI、UTF8、Unicode、Unicode Big Endian)得到的不同二進(jìn)制數(shù)據(jù)。

以英文字符“a”為例,ANSI和UTF8得到的數(shù)值都是“61”,但Unicode將它擴(kuò)充為2個(gè)字節(jié)16位的二進(jìn)制(“61 00”和“00 61”),所以我們又將這種編碼方式稱(chēng)為UTF-16。

UTF-16又可以細(xì)分為2種編碼方式:Big Endian方式與Little_Edian方式,這兩者的唯一區(qū)別在于字節(jié)排列順序剛好相反, Little_Edian方式將“a”編碼為“61 00”,而B(niǎo)ig Endian方式則編碼為“00 61”。

現(xiàn)在看看中文字符,“中國(guó)”兩個(gè)漢字,ANSI編碼為“D6 D0 B9 FA”,4個(gè)字節(jié),一個(gè)漢字占兩個(gè)字節(jié),而UTF8則編碼為“E4 B8 AD E5 9B BD”,6個(gè)字節(jié),一個(gè)漢字占3個(gè)字節(jié)!這說(shuō)明UTF8是一種“變長(zhǎng)”的編碼,可能使用1~4個(gè)字節(jié)來(lái)表示某個(gè)字符。

另外,我們看到UTF8和Unicode編碼(不管是Big Endian還是Little Endian)前面都有幾個(gè)標(biāo)記字符,這些字符放在文本文件的開(kāi)頭,稱(chēng)為“BOM(Byte Order Mark,字節(jié)順序標(biāo)記)”指明了文本的編碼方式,以下是.NET程序中常見(jiàn)的字符編碼方式的BOM值:

編碼

BOM值

UTF-8

EF BB BF

UTF-16  big endian

FE FF

UTF-16  little endian

FF FE

UTF-32  big endian

00 00 FE FF

UTF-32  little endian

FF FE 00 00

了解了上述基礎(chǔ)知識(shí),我們就可以依據(jù)BOM值自動(dòng)檢測(cè)字符串的編碼方式,從而正確從二進(jìn)制數(shù)據(jù)流中解碼,以下代碼檢測(cè)文本二進(jìn)制數(shù)據(jù)是否采用UTF8編碼:

  1. //打開(kāi)文件讀取二進(jìn)制數(shù)據(jù)  
  2. byte[] FileContents = File.ReadAllBytes(FilePath);  
  3. int filelength = FileContents.Length;  
  4. //檢測(cè)BOM  
  5. if (FileContents[0] == 0xef && FileContents[1] == 0xbb && FileContents[2] == 0xbf)  
  6. {    
  7.    //按UTF8解碼字符串,注意要排除掉BOM占用的3個(gè)字節(jié)。  
  8.    String content= Encoding.UTF8.GetString( FileContents, 3, filelength - 3);  
  9.    Console.WriteLine(content);  

其他的編碼方式都可以“依樣畫(huà)葫蘆”。

3 詳解.NET基類(lèi)庫(kù)中與字符編碼相關(guān)的類(lèi)

前述代碼中的Encoding類(lèi)是.NET實(shí)現(xiàn)字符編碼解碼的核心類(lèi)型。圖4展示了它的屬性:

圖 4 Encoding類(lèi)型

如圖4所示,Encoding類(lèi)型提供了UTF8、Unicode等編碼和解碼器,調(diào)用它的Get系列方法完成編碼和解碼工作,以下為示例代碼:

  1. //編碼  
  2. byte[] bytes = Encoding.UTF8.GetBytes("中國(guó)ab");  
  3. foreach (byte value in bytes)  
  4.    Console.Write(" {0}", value.ToString("x")); //轉(zhuǎn)化為16進(jìn)制  
  5. Console.WriteLine();  
  6. //解碼  
  7. char[] chars = Encoding.UTF8.GetChars(bytes);  
  8. foreach (char ch in chars)  
  9.     Console.Write(" {0}", ch); 

運(yùn)行結(jié)果如下:

圖5 編碼和解碼

需要注意的是上述二進(jìn)制值不包括BOM。

事實(shí)上,.NET中的StreamWriter默認(rèn)采用UTF8編碼格式編碼字符串,但并不將UTF8所對(duì)應(yīng)的BOM值(“EF BB BF”)寫(xiě)入到二進(jìn)制流中。以下是StreamWriter的一個(gè)構(gòu)造函數(shù)聲明:

  1. public StreamWriter(string path) : this(path, false, UTF8NoBOM, 0x400)  
  2. {    } 

類(lèi)似地,F(xiàn)ile.ReadAllText()方法在內(nèi)部使用UTF8來(lái)讀取指定文件中的字符串:

  1. public static string ReadAllText(string path)  
  2. {  
  3.     //……  
  4.     return InternalReadAllText(path, Encoding.UTF8);  

由于默認(rèn)編碼方式一致,所以配套使用StreamWriter和File.ReadAllText()方法可以正確地從流中存取字符串。

出于提升代碼可維護(hù)性考慮,正確的用法應(yīng)該是明確地指明編碼方式:

  1. static void WriteFileUseStreamWriterUseUTF8(String fileContent, String FileName)  
  2. {  
  3.     using (StreamWriter writer = new StreamWriter(FileName, false, Encoding.UTF8))  
  4.     {  
  5.                    writer.Write(fileContent);  
  6.     }  

這時(shí),StreamWriter會(huì)在文件開(kāi)頭寫(xiě)入U(xiǎn)TF8的BOM標(biāo)記,從而讓其他的應(yīng)用程序可以很明確地知道本文件中字符串的編碼方式。

4 談?wù)動(dòng)腥さ腅ncoding.Default屬性

Encoding類(lèi)中有一個(gè)有趣的Default屬性,它的類(lèi)型很奇怪,叫作“DBCSCodePageEncoding”,這個(gè)類(lèi)型在MSDN中是查不到的。

“DBCS”代表“double-byte character set(雙字節(jié)字符集)”,它是與“SBCS(single-byte character set,單字節(jié)字符集)”相對(duì)應(yīng)的,SBCS中,所有字符都只占一個(gè)字節(jié),所以能表示的字符數(shù)有限,但在DBCS中,英文字母占一個(gè)字節(jié),漢字等特殊字符占有兩個(gè)字節(jié),從而擴(kuò)充了Windows能顯示的字符數(shù)量。

DBCSCodePageEncoding中的“Code Page”被稱(chēng)為“代碼頁(yè)”,每個(gè)代碼頁(yè)定義了特定的編碼將如何對(duì)應(yīng)于特定的字符(比如簡(jiǎn)體和繁體中文就分別定義在不同的代碼頁(yè)中),因此,同樣的二進(jìn)制數(shù)值,在不同的代碼頁(yè)中,會(huì)代表不同的字符。中文Windows通過(guò)使用基于代碼頁(yè)的DBCS編碼方式,可以方便地以多種編碼方式顯示和處理字符串。

我們?cè)贛SDN中可以查到所有代碼頁(yè)的編號(hào),下面列出了可能比較常用的代碼頁(yè)標(biāo)識(shí):

代碼頁(yè)標(biāo)識(shí)值

.NET中的名字

936

gb2312

950

big5

1200

utf-16

52936

hz-gb-2312

54936

GB18030

65000

utf-7

65001

utf-8

 .NET應(yīng)用程序可以通過(guò)以下方式獲取指定代碼頁(yè)的編碼對(duì)象:

  1. Encoding encode=Encoding.GetEncoding(CodePage); 

以下代碼將按照指定代碼頁(yè)編碼字符串,并將其寫(xiě)入到文件中:

  1. static void WriteFileUseStreamWriterUseCodePage(String fileContent,String FileName,int CodePage)  
  2. {  
  3.    using (StreamWriter writer = new StreamWriter(FileName, false, Encoding.GetEncoding(CodePage)))  
  4.    {  
  5.         writer.Write(fileContent);  
  6.    }  

現(xiàn)在,使用以下代碼將按照UTF8編碼字符串:

  1. WriteFileUseStreamWriterUseCodePage("中國(guó)ab""test.txt", 65001); 

5 結(jié)束語(yǔ)

除了本文所介紹的將字符串保存到文本文件的這種場(chǎng)景,字符串的編碼方式在基于套接字的TCP/UDP網(wǎng)絡(luò)編程也非常重要,比如.NET提供了一個(gè)NetworkStream封裝Socket實(shí)現(xiàn)網(wǎng)絡(luò)通訊,如果希望將一個(gè)命令字符串從客戶(hù)端送到服務(wù)端,服務(wù)端通過(guò)讀取這個(gè)字符串完成特定的工作,則編碼方式就很重要了,客戶(hù)端與服務(wù)端必須采用一致的編碼方式傳送命令,否則,網(wǎng)絡(luò)服務(wù)就有可能因?yàn)闊o(wú)法解析客戶(hù)端發(fā)送過(guò)來(lái)的數(shù)據(jù)而Down掉。有關(guān)網(wǎng)絡(luò)編程的內(nèi)容很有趣,我的下一篇文章會(huì)介紹.NET套接字編程。

好了,這篇介紹字符串編碼的短文寫(xiě)完了,希望本文能對(duì)讀者有所幫助,如有錯(cuò)誤,敬請(qǐng)指正。

原文鏈接:http://www.cnblogs.com/bitfan/archive/2010/11/25/1887590.html

【編輯推薦】

  1. .NET Framework字符串相關(guān)操作細(xì)節(jié)介紹
  2. 詳解.NET字符串解析的具體過(guò)程
  3. 改進(jìn)C#連接字符串的性能
  4. .NET Lambda表達(dá)式的語(yǔ)義:字符串列表范例
  5. C#字符串的幾種常用方法

 

責(zé)任編輯:彭凡 來(lái)源: 博客園
相關(guān)推薦

2024-04-01 08:41:39

字符串.NET

2009-10-13 16:09:27

.NET字符串解析

2016-05-12 15:51:08

前端開(kāi)發(fā)字符編碼

2024-06-11 07:34:58

C#字符串性能

2015-10-29 11:55:30

.NET空白字符串方法

2015-08-13 10:42:49

.NET空白字符串

2022-05-18 10:56:58

Java字符串編碼

2010-06-28 15:18:51

SQL Server

2010-03-03 09:12:25

.NET字符串拘留池

2009-07-24 11:12:33

ASP.NET連接字符

2011-06-21 10:26:37

2009-10-16 13:04:57

VB.NET字符串?dāng)?shù)組

2009-11-12 11:09:56

ADO.NET連接字符

2009-02-24 15:39:27

字符串比較函數(shù)函數(shù)

2011-06-08 15:45:41

字符串JAVA

2021-09-07 09:23:07

C++字符串算法

2011-07-11 16:00:22

字符串拼接

2020-09-03 10:13:49

JavaScript字符串pad

2025-06-30 02:11:00

2021-03-11 18:44:39

字符串SQL表達(dá)式
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 在线观看中文字幕视频 | 丝袜美腿一区 | 在线观看亚 | 国产在线不卡视频 | 日中文字幕在线 | 中文字幕精品一区久久久久 | www.v888av.com| 久草青青草 | 91麻豆精品国产91久久久更新资源速度超快 | 久久久综合精品 | 国产精品99久久久久久宅男 | 一区视频在线免费观看 | 97视频在线观看网站 | 亚州中文 | 成人在线播放 | 亚洲高清中文字幕 | 91精品久久久久久久久久 | 亚洲日本一区二区三区四区 | 国产精品v| 青青操av | 欧美激情一区二区三区 | 日本a∨精品中文字幕在线 亚洲91视频 | 黄网站在线播放 | 操久久| 久久91精品| 欧美1区2区 | 亚洲国产中文在线 | 亚洲二区视频 | www.中文字幕.com | 日日综合 | 人妖av| 农村真人裸体丰满少妇毛片 | 国产日韩欧美精品一区二区 | 成人免费视频网站在线看 | 国产丝袜一区二区三区免费视频 | 亚洲国产精品一区二区久久 | www精品美女久久久tv | 亚洲一区二区三区在线 | 91成人在线 | 久久久网| 精品久久久久久久久亚洲 |