当前位置: 首页 > news >正文

C#的CSV 在8859-1下中乱码和技巧

1. 写在前面:

并不代表我解决了这个问题,主要还是笔记

原因是CSV出现乱码的原因多种多样。
所以,我没有能力列举出所有的可能性。只是一个issue一个issue地解说。
主要与是否有BOM头和编码格式有关。

1.1 问题和问题复杂化的原因

问题是读CSV时中文乱码,主要是描述8859-01的情况.
问题复杂化的原因:
(1)C#语言的局限性。
(2)需要使用CsvHelper的CsvReader来读取。实际上,如果自己手工处理,很可能不会遇到这个问题。
(3)8859-1,一般而言,如果是标准的含BOM头 , 以及 文件是标准的UTF-8, 是不会遇到这个问题的。

1.2 乱码出现的原理

CSV的全称是:逗号分隔值(Comma-Separated Values,CSV);
所以,这个‘,’很重要,如果不能识别出这个是分隔符,还是一内容的一部分,就会出乱码。

2. ISO 8859-1

网上看到的多是UTF-8格式

但是不清楚,是否是我的操作问题,我是用Excel标准方式操作,存出来的CSV,还是ASCⅡ 格式。(印象中以前不是这样的,所以,这里只当是疑问)。

啊对,这里稍提一句,“其实计算机是8进制的”,突然想到大学的老师给我们讲的这句,一直没明白。其实0x55, 这样的16进制,是由两个8进制组成。因为英语体系的人发明计算机时,认为127个可见字符,加一些扩展字符就够用了。当然不是什么硬件原因!只是一个简单的需求+实现的具现化。2的7次方是127。

通用技巧之file

知道当前的csv是什么字符编码的,很重要。
如果需要(事实上一定是需要的,而且是第一步),装好git后,或者如果你有linux,先看一下它怎么说:

file my.csv

例如
在这里插入图片描述
我将8859-1放在这里,是反馈标题:实际上,对于大多数计算机语言来讲,ASC-Ⅱ码,根本就不是问题。因为那是它们天生的模式。
但对C#来讲,反而是最困难的。因为其特化的Encoding只有这几个:
在这里插入图片描述
可能有人认为Default或者ASCII是可以的,这个读者们,可以帮我查一下Default是什么,可能是Unicode-16的,而ASCII是不是与8859一样呢?理论上一样,但实际不一样。
因为8859多某种角度来说,还真有点像UTF-8,只是,不像UTF-8事实上有起始标记位,8859没有。
解决的办法是很简单的:

                // 读取文件内容
                byte[] fileBytes = File.ReadAllBytes(defectCodeMappingPath);
                using (var stream = new MemoryStream(fileBytes))
                //using (var reader = new StreamReader(stream, Encoding.UTF8)) //wrong
                //ISO-8859 encoding,  GBK or UTF-8 
                using (var reader = new StreamReader(stream, Encoding.GetEncoding(936)))  //ok

即用:Encoding.GetEncoding(936) 代替即可。
然后

using (var csv = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture)))

3. UTF-8与BOM

虽然CSV有许多种可能,我们如果认为微软心中的标准,那么就是BOM头(3bytes)+ UTF-8.
这种情况,也是需要考虑的。
例如,这是一段我写的代码


        public bool ReduceCsv_v2(string inputdataall_file,ref CsvMemObj curCsvObj)
        {
            try
            {
                lstAllSeg.Clear();
                using (var reader = new StreamReader(inputdataall_file))
                using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
                {
                    var inputData = csv.GetRecords<PadItem>();//.ToList(); 

                    var qrySegNgs = from cust in inputData group cust by cust.MountNb;

                    // customerGroup is an IGrouping<string, Customer>
                    foreach (var customerGroup in qrySegNgs)
                    {
                        //Console.WriteLine(customerGroup.Key);
                        lstAllSeg.Add(int.Parse(customerGroup.Key));
                        //List<int> lstNgSeg = new List<int>();
                    }
                    lstAllSeg.Sort();
                    reader.Close();
                    csv.Dispose();
                }

                foreach (var item in lstAllSeg)
                {
                    curCsvObj.lstPannels.Add(new Panel(item));
                }
                return true;
            }
            catch (System.Exception ex)
            {
                GenUtils.MyErrExcu.E(ex);
                return false;
            }
        }

这里没有CSV相关编码转换的过程,
是因为在之前我处理好了.
即有一个程序,收到文件后,进行检查和转换: 有无BOM头,如果没有则补上, 如果是其它的编码, 转为UTF-8.
然后就可以了。
类似这样:

public class CvsCovertUtf8
    {

        private static Lazy<CvsCovertUtf8> _Instance = new Lazy<CvsCovertUtf8>(() => new CvsCovertUtf8());

        public static CvsCovertUtf8 Instance
        {
            get
            {
                return _Instance.Value;
            }
        }
        public string ScrFolderPath { get; set; }
        public string TargetFolderPath { get; set; }
        //成功,将ASC,转为utf-8
        public bool CovertAsc2Utf8(string absSrcFilePath,string absDestFilePath)
        {
            try
            {
                if (!File.Exists(absSrcFilePath))
                {
                    MyLogInfo.LError("FileDoesNotExist:" + absDestFilePath);
                    return false;
                }
                if (File.Exists(absDestFilePath))
                {
                    MyUtils.DelGenFile(absDestFilePath);
                }
                using (StreamReader sr = new StreamReader(absSrcFilePath, Encoding.Default))
                using (StreamWriter sw = new StreamWriter(absDestFilePath, false, Encoding.UTF8))
                {
                    string strtxt = sr.ReadToEnd();
                    sw.Write(strtxt);
                    sw.Flush();
                    sw.Close();
                    sr.Close();
                }
                return true;
            }catch(System.Exception ex)
            {
                MyErrExcu.E(ex);
                return false;
            }

        }
    }

4. 探测和添加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)
                {
                    byte[] fileWithBom = new byte[bom.Length + fileBytes.Length];
                    bom.CopyTo(fileWithBom, 0);
                    fileBytes.CopyTo(fileWithBom, bom.Length);
                    fileBytes = fileWithBom;
                } 不能加bom头,加入后乱码

                using (var stream = new MemoryStream(fileBytes))
                using (var reader = new StreamReader(stream, Encoding.GetEncoding(936)))  //ok
                using (var csv = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture)))

上面这个是原始版本,我想虽然思路是对的,但少了一步转为UTF-8.
也就是说,BOM头一定是与UTF-8相伴生的.也可能是UTF-16,但肯定是不可能与 8859这样的编码并存.

小结

以内就是全部内容。
即两条路线:
一条是坚持8859到头;Encoding.GetEncoding(936)
一条是任你输入千万,最终都是UTF-8. 这条需要将后面的两节合并才能确保实现。

http://www.dtcms.com/a/99637.html

相关文章:

  • 猜猜我用的是哪个大模型?我的世界游戏界面简单的模拟效果
  • 网络华为HCIA+HCIP 策略路由,双点双向
  • OSPF练习
  • Let’s Encrypt 宣布推出短期证书与 IP 地址支持,推动 Web 安全迈向新高度
  • 无线通信技术(二):ITU、3GPP及传统波段对无线频谱的划分
  • AutoDev 2.0 正式发布:智能体 x 开源生态,AI 自动开发新标杆
  • 计算机组成原理笔记(六)——2.2机器数的定点表示和浮点表示
  • React Router精通:轻松创建动态单页应用
  • 动态IP:网络世界的“变色龙”如何改变你的在线体验?
  • 革新汽车安全通信技术,美格智能全系车载通信模组支持NG-eCall
  • Baklib知识中台驱动智能架构升级
  • HTML布局
  • HTML文档流
  • Turtle事件处理(键盘与鼠标交互)
  • 基于单片机的智能家居设计(论文+源码)
  • RabbitMQ 技术详解:异步消息通信的核心原理与实践
  • wordpress的cookie理解
  • 【AI学习】机器学习算法
  • 内网渗透-ICMP隧道
  • javaScript Vue2的高级用法
  • 微型导轨和普通导轨有哪些区别?
  • 如何在ms-swift 微调训练deepseekvl2时使用sageattention
  • flutter优秀项目推荐
  • 【Spring Boot 与 Spring Cloud 深度 Mape 之五】微服务守门神:Spring Cloud Gateway 核心详解与实战
  • Linux下xl9535 gpio扩展芯片bug调试
  • Java面试黄金宝典16
  • C语言_数据结构_排序
  • LeetCode 每日一题 2025/3/24-2025/3/30
  • Typora使用Gitee作为图床
  • Windows模仿Mac大小写切换, 中英文切换