求助:C#读文本文件(编码未知)的问题

    现有文本文件“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#如何才能无误的读取数据呢?

转载于:https://www.cnblogs.com/xiongxuanwen/archive/2012/03/02/2377261.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值