zoukankan      html  css  js  c++  java
  • 求助: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#如何才能无误的读取数据呢?

  • 相关阅读:
    常见的四种文本自动分词详解及IK Analyze的代码实现
    用java语言通过POI实现word文档的按标题提取
    spark的运行模式
    团队冲刺日志2
    简单之美-软件开发实践者的思考 03
    简单之美-软件开发实践者的思考 02
    简单之美-软件开发实践者的思考 01
    学习进度 15
    构建之法 06
    构建之法 05
  • 原文地址:https://www.cnblogs.com/xiongxuanwen/p/2377261.html
Copyright © 2011-2022 走看看