这里写自定义目录标题
欢迎使用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了。
真的是让人很难接受这样的结果。
完全是让人很困惑。
但这就是今天的程序。