求助:C#讀文字檔(編碼未知)的問題

來源:互聯網
上載者:User

    現有文字檔“test.txt”(使用vc儲存的,具體格式編碼未知),只有2行字串,如所示:

圖1

    其行資料是按照一定格式排列的,前6個位元組表示是人名(字串),後2個位元組表示年齡(整形值)。例如第一行“熊選文28”,表示熊選文的年齡是28歲。注意,第二行其中的”?”不是中文的問號,也不是英文的問號,只是Windows系統沒有對應字元,才顯示? 。如,該“?”對應的兩個位元組:C6 32。

圖2

    根據的16進位位元組編碼推測,該文本應該不是UNICODE編碼,因為頭部沒有BOM。

    現在要求用C#編寫程式來讀上面這個文字檔,並將每行的人名和年齡分別提取出來。

    很簡單,用StreamReader就可以,代碼如下:

public void ReadFileData(string fileName)

{

    //System.Text.Encoding encode=System.Text.Encoding.Default;

    System.Text.Encoding encode=System.Text.Encoding.GetEncoding("gb2312");

    //default表示使用作業系統的編碼即可,一般中文作業系統都是Encoding.GetEncoding("gb2312"),但是其他系統就不一樣了

    //所以,此處其實用Encoding.GetEncoding("gb2312")更精確一些,免得有時候換成英文或其他動作系統,讀取資料就有問題了

    using(StreamReader sr = new StreamReader(fileName, encode))

    {

        if (sr == null)

        {

            return;

        }

        int nRow=0;//行號

        string sLineBuf = null;//行資料緩衝

        string sName = "";//人名

        int nAge = 0;// 年齡

        while ((sLineBuf = sr.ReadLine()) != null)//

        {

            nRow++;

            if (sLineBuf == "")

                continue;//如果為空白字串,跳過當前行

            sName =GetSubString(sLineBuf, 0, 6);//讀取人名(前6個位元組)

            string sAge =GetSubString(sLineBuf, 6, 2);//後2個位元組

            nAge = Convert.ToInt16(sAge);//讀取年齡

        }

    }

    因為字串內建的取子字串的函數Substring()是按字元數來截取的,而不是按照位元組數來截取。故我自己寫了一個按照位元組數來截取子字串的函數:GetSubString。

/// <summary>

/// 從一個字串中某個位置(該位置以位元組數而不是字元數計算)開始取定長(該字串的長度以位元組數而不是字元數計算)的字串

/// </summary>

/// <param name="SStr">源字串</param>

/// <param name="nStart">取字串的起始位置</param>

/// <param name="nByte">字串的長度</param>

/// <returns>返回字串</returns>

public static string  GetSubString(string SStr,int nStart,int nByte)

{

    string Tstr = "";

    byte[] sbytes = System.Text.Encoding.GetEncoding("gb2312").GetBytes(SStr);//轉換為位元組數組

    if (sbytes.Length == 0)

        return Tstr;

    if (nStart > sbytes.Length)

        return Tstr;

    byte[] tbytes = new byte[nByte];

    int i = nStart;

    int j = 0;

    while (i < sbytes.Length && j < nByte)

    {

        tbytes[j++] = sbytes[i++];

    }

    try

    {

        Tstr = System.Text.Encoding.GetEncoding("gb2312").GetString(tbytes);//轉換為字串

    }

    catch (System.Exception ex)

    {

        throw ex;

    }

    return Tstr;

}

    上面的程式寫好了,開始讀取資料,輸出結果如下: 

人名:年齡

熊選文:28

張三?2:0

    第一行資料是沒問題,但第二行就有問題了。本來應該是"張三?"的年齡是"20"歲,讀出來的結果是"張三?2"的年齡是"0"歲,明顯有誤。為什麼會出現這樣的結果呢?

    通過調試,就會發現c#讀取該行的十六進位為:D5 C5 C8 FD 3F 32 30,而原本應該是D5 C5 C8 FD C6 32 32 30(見圖2)。原本的C6 32變成了3F3F對應的字元就是英文的問號),所以位元組數就少了一個,截取前6個位元組就是D5 C5 C8 FD 3F 32,對應的字串就是“張三?2”,後面只有一個位元組30,對應的字元就是0。所以最後得到的結果是“張三?2”的年齡是“0”。

    通過對比分析發現,第一行資料中沒有像“C6 32”這樣的字元,所以用c#讀出來結果很正常。第二行中有“C6 32”這樣的字元,用C#讀就會自動轉換為3F。如果把“C6 32”換成其他的字元,如“BD 32”,都會有同樣的問題。這是為什麼呢?我想,應該是在GB2312中沒有這種字元編碼,所以無法識別,將該字元自動轉換為英文的”?”,當然也無法正確讀和顯示了。

    像上面這種文本資料(文本編碼方式未知,但包含中英文,甚至有除中英文之外的其他字元),用C#如何才能無誤的讀取資料呢?

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.