【csvHelper】的工程笔记

欢迎使用Markdown编辑器

这两年看来是要在大部分时间用c#了。
我自己为掌握得非常好的c++一时是用不上了。
关于Excel我一直自认是专家,从上学时就用,那些年VB反而用得多。行吧。
这几天又要解析csv,之前我习惯解文件,或用excel oem来操作excel。
在工业上 ,csv是比较常见了。
今天又花了几个小时时间。

之前处理过一次,这次忘记了。但后来感觉是我csvHelper用错了。
今天也没有搞清楚,只能记在这里了

新的改变

        private void LoadTranslationMap()
        {
            string defectCodeMappingPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DefectCodeMapping.csv");
            if (!File.Exists(defectCodeMappingPath))
            {
                Logger.Warn($"File not found: {defectCodeMappingPath}. Loading default defect code mapping.");
                LoadDefaultMapping();
                return;
            }

            try
            {

                // 读取文件内容
                byte[] fileBytes = File.ReadAllBytes(defectCodeMappingPath);

                // UTF-8 BOM
                byte[] bom = Encoding.UTF8.GetPreamble();

                // 检查文件是否包含BOM
                bool hasBom = fileBytes.Length >= bom.Length && fileBytes.Take(bom.Length).SequenceEqual(bom);

                // 如果文件没有BOM,手动添加BOM
                if (!hasBom)
                {
                    // 创建一个新的字节数组,包含BOM和文件内容
                    byte[] fileWithBom = new byte[bom.Length + fileBytes.Length];
                    bom.CopyTo(fileWithBom, 0); // 将BOM复制到新数组的开头
                    fileBytes.CopyTo(fileWithBom, bom.Length); // 将文件内容复制到新数组
                    fileBytes = fileWithBom; // 更新fileBytes为带BOM的字节数组
                }

                // 使用带BOM的字节数组创建MemoryStream
                using (var stream = new MemoryStream(fileBytes))
                using (var reader = new StreamReader(stream, Encoding.UTF8))
                using (var csv = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture)))
                {
                    if (csv.Read())
                    {
                        // 读取CSV文件的头部信息(列名)
                        var headers = csv.ReadHeader();
                        if (headers == null)
                        {
                            Console.WriteLine("CSV文件中没有列头信息!");
                            return;
                        }

                        // 打印列名
                        Console.WriteLine("列名:");
                        foreach (var header in csv.HeaderRecord)
                        {
                            Console.Write($"{header}, ");
                        }
                        Console.WriteLine();
                    }

                    while (csv.Read())
                    {
                        var deviceCode = csv.GetField("INSP_FAULT_CODE");
                        var mesCode = csv.GetField("MES_DEFECT_CODE");
                        _translationMap[deviceCode] = mesCode;
                    }
                }

                Logger.Info("Defect code mapping loaded successfully from CSV.");
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Error loading defect code mapping from CSV. Loading default mapping.");
                LoadDefaultMapping();
            }
        }

解读

BOM问题

这里之前我是搞懂了的,但当时没有记笔记,找不到了,所以,今天我这里想写下来。
但这次是真没有搞清楚。。。

BOM(Byte Order Mark)
CSV文件,一般是UTF-8的,这种文件有两种,一种是有三个byte BOM头的,一种是没有的。
而微软的Excel显然是要求有的。
没有它是不认的。
结果就是乱码。
其实乱码也没有什么,但事实上,微软也没有保护,CSV的意思是:
CSV 是 “Comma-Separated Values”
关键是 Comma 会被乱码所包围。以致于文件的内容被破坏。
所以,乱码,的确有问题。
所以,上面的代码,前一部是,检查是否有BOM头,没有则加上。

                // 读取文件内容
                byte[] fileBytes = File.ReadAllBytes(defectCodeMappingPath);

                // UTF-8 BOM
                byte[] bom = Encoding.UTF8.GetPreamble();

                // 检查文件是否包含BOM
                bool hasBom = fileBytes.Length >= bom.Length && fileBytes.Take(bom.Length).SequenceEqual(bom);

                // 如果文件没有BOM,手动添加BOM
                if (!hasBom)
                {
                    // 创建一个新的字节数组,包含BOM和文件内容
                    byte[] fileWithBom = new byte[bom.Length + fileBytes.Length];
                    bom.CopyTo(fileWithBom, 0); // 将BOM复制到新数组的开头
                    fileBytes.CopyTo(fileWithBom, bom.Length); // 将文件内容复制到新数组
                    fileBytes = fileWithBom; // 更新fileBytes为带BOM的字节数组
                }

                // 使用带BOM的字节数组创建MemoryStream
                using (var stream = new MemoryStream(fileBytes))
                using (var reader = new StreamReader(stream, Encoding.UTF8))
                using (var csv = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture)))

##csvHelper 读取的问题

事实上,csvHelper的文档,挺难读的,友好性不高。
误导的不止是人类啊,就是AI也受害。
事实上,AI很难写出来不出错的csvhelper程序。
除非,你严格按照csvHelper设计者的想法,先整体读入,然后再对象化。
但事实上,在工业领域,很多时候,对像化反而是有害的,因为我们大多数层级,都是信息的传递者,而不是consumer,我们只是搬运工。
所以,出问题是常见情况。
下面的代码我是改好了的,
意思是说,我们需要先读一行,然后把head line消费掉,然后再读数据。
否则就出错啊。
而且出错得信息,让人找不着北。
所以,这里写下来,至少给自己自己提个醒。
以后我会逐渐完善这个系列。

if (csv.Read())
                    {
                        // 读取CSV文件的头部信息(列名)
                        var headers = csv.ReadHeader();
                        if (headers == null)
                        {
                            Console.WriteLine("CSV文件中没有列头信息!");
                            return;
                        }

                        // 打印列名
                        Console.WriteLine("列名:");
                        foreach (var header in csv.HeaderRecord)
                        {
                            Console.Write($"{header}, ");
                        }
                        Console.WriteLine();
                    }

                    while (csv.Read())
                    {
                        var deviceCode = csv.GetField("INSP_FAULT_CODE");
                        var mesCode = csv.GetField("MES_DEFECT_CODE");
                        _translationMap[deviceCode] = mesCode;
                    }

后记

这就么多吧。
原来的代码,在Load后,直接这样就出错了。

                    while (csv.Read())
                    {
                        var deviceCode = csv.GetField("INSP_FAULT_CODE");
                        var mesCode = csv.GetField("MES_DEFECT_CODE");
                        _translationMap[deviceCode] = mesCode;
                    }

然后把head line跳过就OK了。
真的是让人很难接受这样的结果。
完全是让人很困惑。
但这就是今天的程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值