[轉]C#的二進制文件操作及關於Encoding類與漢字編碼轉換的問題


1.數值應保存在二進制文件

首先列舉文本、二進制文件的操作(讀寫)方法:
方式1:
//文本文件操作:創建/讀取/拷貝/刪除
using System;
using System.IO;
class Test 
{
   string path = @"f:/t.txt";
   public static void Main() 
   {       
      //創建並寫入(將覆蓋已有文件)
      if (!File.Exists(path))
      {
//StreamWriter m=new           
//StreamWriter(path,true,Encoding.Default,1);//ASCII,1   Encoding.Default:即//UTF-8編碼 這樣就可以指定編碼方式
    using (StreamWriter sw = File.CreateText(path))
         {
            sw.WriteLine("Hello");
         } 
      }
      //讀取文件
      using (StreamReader sr = File.OpenText(path)) 
      {
        string s = "";
        while ((s = sr.ReadLine()) != null) 
        {
           Console.WriteLine(s);
        }
     }
     //刪除/拷貝
     try 
     {
        File.Delete(path);
        File.Copy(path, @"f:/tt.txt");
     } 
     catch (Exception e) 
     {
        Console.WriteLine("The process failed: {0}", e.ToString());
     }
   }
}

方式2:

//流文件(二進制)操作
private const string name = "Test.data";
public static void Main(String[] args) 
{
    //打開文件()  ,或通過File創建立如:fs = File.Create(path, 1024)
    FileStream fs = new FileStream(name, FileMode.CreateNew);
    //轉換為字節寫入數據(可寫入中文)
    Byte[] info = new UTF8Encoding(true).GetBytes("This is some text in the file.");
    //字節數組,字節偏移量,最多寫入的字節數
BinaryWriter   w   =   new   BinaryWriter(fs);
//設置要寫入的偏移量  
fs.Position=fs.Length;
  //  fs.Write(info, 0, info.Length);   這個也可以
    w.Close();
    fs.Close();
    //打開文件
    fs = new FileStream(name, FileMode.Open, FileAccess.Read);
    //讀取
    BinaryReader r = new BinaryReader(fs);
    for (int i = 0; i < 11; i++) 
    {
        Console.WriteLine(r.ReadInt32());
    }
    w.Close();
    fs.Close();

在將一系列二進制數如方式1寫入到file.txt(二進制)文件后,打開file.txt后顯示的數據二進制數有些錯誤,有些正確。(與存入的不一樣)向文件中寫入的默認(也可以設置)都是使用UTF-8編碼。打開file.txt是也是默認UTF-8編碼。   若將其如方式2存入二進制文件,則顯示的數據一致。若將二進制數(整數)保存為文本文件出錯。二進制文件是直接寫入文件的(磁盤)沒有經過編碼和讀取時的解碼。

2.關於Encoding

CLR中的Encoding是在System.Text命名空間下的,它是一個抽象類(abstract class),  所以不能被直接實例化,它主要有如下的派生類:ASCIIEnding,UnicodeEncoding,UTF32Encoding,UTF7Encoding,UTF8Encoding,你可以根據需要選擇一個合適的Encoding來進行編碼和解碼。你也可以調用Encoding的靜態屬性ASCII,Unicode,UTF32,UTF7,UTF8,來構造一個Encoding。其中Unicode是表示16位Encoding。調用靜態屬性和實例化一個子類的效果是一樣的,如下代碼。

Encoding encodingUTF8 = Encoding.UTF8;
Encoding encodingUTF8 = new UTF8Encoding(true);

以下是這些類型的一些簡單描述:

      ASCII編碼  將16位字符編碼成ASCII碼,只能轉換值小於Ox0080的16字符,並且被轉換成單字節,就是說一個字符對應一個字節。當字符都在ASCII范圍(0X00~0X7F)內時,可以用這種編碼,它的速度非常快,適合於英美地區的字符。這種編碼非常有限,漢字會被轉換成亂碼。在CLR對應ASCIIEndoing。

      UTF-16     每個字符編碼成2個字節,它不會對字符產生任何影響,也不會涉及到壓縮處理,性能非常好,因為CLR中的字符也是16位的Unicode。在CLR中對應UnicodeEncoding。

      UTF-32     使用4個字節編碼成一個字符。從內存角度上講,它並不是一種高效能的編碼方案,因為第個字符都是4個字節,特別占內存,所以很少用來做文件和網絡流的編碼解碼。在CLR中對應UTF32Encoding。

      UTF-8      值在Ox0080之下的字符壓縮成一個字符,也就是ASCII碼;值在0X0080---0X07FF之間的字符都轉換成2個字符,適合用於歐洲和中東地區。0X0800以上被轉換成3個字符,適合於東亞地區的字符。代理項被轉換成4個字節。因此,它是一種非常流行的編碼,適用於互聯網。它在處理0X0800以上的字符效率不好UTF-16。在CLR中對應UTF8Encoding。

      UTF-7     這咱編碼通常用於舊的系統,那時的系統是用7位值表示。目前已經被Unicode協淘汰。在CLR中對應UTF7Encoding。

     從性能角度上來講,如果你的代碼需要在多處調用一個Encoding,微軟建議你使用靜態成員的方式構造一個Encoding對象,而不是構造實例。它的內部實現是一個單例模式。

   如果你知道某種編碼的代碼頁(code page)或名字,那么你可以調用Encoding的靜態方法GetEncoding(int codepage),GetEncoding(string name)來構造一個Encoding,比如我們常用的用於顯示簡體中文的gb2312,它的代碼頁是936,我們就可以這樣定義:

Encoding encodingGB2312=Encoding.GetEncoding("gb2312");
Encoding encodingGB2312=Encoding.GetEncoding(936);

  目前有幾十種文字代碼頁,分別對應於不同的國家,不同的語言,它們只是對應Unicode字符集里的相一部分,比如說936,它只是對應於Unicode字符集里簡體中文的那一部分,如果你想正確的顯示繁體字,那么就要用中文繁體對應的代碼頁950。具體的代碼頁有哪些可以參考MSDN或園子里這篇文章,C#文字代碼頁,文字編碼的代碼頁名稱速查表

  Encoding對象有一個靜態屬性Default,它返回的也是一個Encoding對象,至於返回哪個語言的Encoding取決於你電腦里-->控制面板->區域和語言 里面的設置,也就是ANSI。如下圖,我電腦里設置是Chinses(Simplified, PRC)也就是簡體中文,那么對應的就是gb2312,所以下面代碼會打印gb2312。如果你的代碼在不止一個國家里使用,那么你最好不要Encoding.Default,這樣會造成亂碼,你最好用Encoding.UTF8。

3.漢字編碼轉換相關:

  UNICODE是為了處理包括中文,日文等字符而提出的一種通用的字符集。最初的UNICODE為雙字節字符集,即16位編碼,能夠包括65536個字符。但這樣的容量並不能滿足所有需要,因此,現在的UNICODE已經擴展到4個字節,能夠容納1,112,064 個字符,而這些在16位之后的擴展背稱為增補字符。

  UTF-32、UTF-16 和 UTF-8 是 Unicode 標准的編碼字符集的字符編碼方案。

  UTF-8 使用一至四個字節的序列對編碼 Unicode 代碼點進行編碼。U+0000 至 U+007F 使用一個字節編碼,U+0080 至 U+07FF 使用兩個字節,U+0800 至 U+FFFF 使用三個字節,而 U+10000 至 U+10FFFF 使用四個字節。UTF-8 設計原理為:字節值 0x00 至 0x7F 始終表示代碼點 U+0000 至 U+007F(Basic Latin 字符子集,它對應 ASCII 字符集)。這些字節值永遠不會表示其他代碼點,這一特性使 UTF-8 可以很方便地在軟件中將特殊的含義賦予某些 ASCII 字符。

  GB2312(1980年)一共收錄了7445個字符,包括6763個漢字和682個其它符號。漢字區的內碼范圍高字節從B0-F7,低字節從A1-FE,占用的碼位是72*94=6768。其中有5個空位是D7FA-D7FE。當然也可以表示數字和字符(一個字節,與ASCII表示相同)。

要讀取一個以GB2312編碼的包含漢字、數字、字母的二進制文件。
String strName =Encoding.GetEncoding("gb2312").GetString(name,0,i) ;
// name是讀取的二進制數組。
這樣就能將二進制數組轉換為漢字、數字或字母
 
同樣:也可以將包含漢字、數字、字母的字符串轉換為二進制數組保存到二進制文件。
String unicodeString =   "備用43E";
Byte[] encodedBytes = Encoding.GetEncoding("gb2312").GetBytes(unicodeString);
 
當然也可以進行二進制數組與UNICODE,UTF-8等編碼方式的轉換
Byte[] encodedBytes = utf8.GetBytes(unicodeString);
String decodedString = utf8.GetString(encodedBytes);
 
UnicodeEncoding unicode = new UnicodeEncoding();
Byte[] encodedBytes = unicode.GetBytes(unicodeString);
String decodedString = unicode.GetString(encodedBytes);

原文鏈接:C#的二進制文件操作及漢字編碼轉換

 

其它有價值的鏈接:

1、字符集和字符編碼(Charset & Encoding)

2、C# Encoding

3、C# 小敘 Encoding (一)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM