C# Winforms - 读取 csv 文件时出现问题
C# Winforms - Issue reading a csv file
我已经查看了我能找到的所有 csv 阅读示例,但我不太确定我哪里出错了。
我对 C# 还很陌生,但到目前为止我很喜欢它!
无论如何,这里的代码在 大多数 的时候都很好用(你可以从评论中看到我在阅读中尝试了很多不同的选项):
StreamReader sr = new StreamReader(csvFileToImport);
while (sr.EndOfStream != true)
{
string line = sr.ReadLine();
//string[] value = line.Split(new string[] { "\",\"" }, StringSplitOptions.None);
//string[] value = line.Split(new string[] {","}, StringSplitOptions.None);
//string[] value = line.Split(new string[] { "(?=(?:[^']*'[^']*')*[^']*$)" }, StringSplitOptions.None);
//string[] value = line.Split(new string[] { "," }, StringSplitOptions.None);
string[] value = Regex.Split(line, @"\s|[,]");
StockItem si = new StockItem();
switch (stockFile.Supplier)
{
case "Leader":
si.Supplier = stockFile.Supplier;
si.Category = value[2].Replace("'", "''");
si.StockCode = value[11].Replace("'", "''");
si.Cost = Convert.ToDecimal(value[7]);
si.Description = value[4].Replace("'", "''");
si.Image = value[9].Replace("'", "''");
si.Manufacturer = value[10].Replace("'", "''");
si.Sell = Convert.ToDecimal(value[8]);
si.StockAdelaide = value[17].Replace("'", "''");
si.StockBrisbane = value[18].Replace("'", "''");
si.StockMelbourne = value[19].Replace("'", "''");
si.StockPerth = value[20].Replace("'", "''");
si.StockSydney = value[21].Replace("'", "''");
si.Subcategory = value[3].Replace("'", "''");
//Add line into db
string sql = "insert into Stock (Supplier, StockCode, Manufacturer, Category, Subcategory, Description, Cost, Sell, Image, StockPerth, StockAdelaide, StockSydney, StockBrisbane, StockMelbourne) values ('" + si.Supplier + "', '" + si.StockCode + "', '" + si.Manufacturer + "', '" + si.Category + "', '" + si.Subcategory + "', '" + si.Description + "', " + si.Cost + ", " + si.Sell + ", '" + si.Image + "', '" + si.StockPerth + "', '" + si.StockAdelaide + "', '" + si.StockSydney + "', '" + si.StockBrisbane + "', '" + si.StockMelbourne + "')";
cmd = new SqlCommand(sql, cn);
cmd.ExecuteNonQuery();
break;
default:
break;
}
}
success = true;
cn.Close();
我已经链接到一个 1 行的 csv 文件,如果有人愿意看一下,我将不胜感激!
提前致谢,也请随时指出我可以改进的任何通用代码...我相信还有很多地方需要改进。
再次感谢:)
CSV Link: https://www.dropbox.com/s/nnaruu0twds3wrl/csv_error.csv?dl=0
更新:
很抱歉不够清晰,因为我在阅读文件时收到以下错误:
System.FormatException: 'Input string was not in a correct format.'
该行内容如下:
"MECMD4VL2X426,ME,Memory,DDR-4 (Desktop),Corsair Vengeance LPX 8GB (2x4GB) DDR4 2666MHz C16 Desktop Gaming Memory Black,\"Corsair 8GB (2x4GB) DDR4 2666MHz Vengeance LPX Black"
当我查询数组时,它显示的值为:
value[0] "MECMD4VL2X426"
value[1] "ME"
value[2] "Memory"
value[3] "DDR-4"
value[4] "(Desktop)"
value[5] "Corsair"
value[6] "Vengeance"
value[7] "LPX"
...
它似乎卡在括号中(应该读入值 [3]),然后开始在 space 而不是逗号上分隔。
如果需要,我很乐意使用第 3 方 csv reader,但是我很想自己了解它是如何工作的。
读取您使用 string line = sr.ReadLine();
但 RFC 4180 的 csv,
2.6 告诉我们一个包含多行的字段应该用DQuote封装 "
.
因此,如果您的文档中存在这些多行字段,则逐行读取文件将是一个问题。
我会放弃手工制作的正则表达式和 ReadLine
并使用更强大的解析器,如 CSV Helper.
然后定义要从 CSV 中获取的对象。
public class Leader
{
public string LongColumn6 { get; set; }
public string Supplier { get; set; }
public string Category { get; set; }
public string StockCode { get; set; }
public Decimal Cost { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public string Manufacturer { get; set; }
public Decimal Sell { get; set; }
public string StockAdelaide { get; set; }
public string StockBrisbane { get; set; }
public string StockMelbourne { get; set; }
public string StockPerth { get; set; }
public string StockSydney { get; set; }
public string Subcategory { get; set; }
}
它是各自的映射器:列 & 是 Foo 属性等。
public sealed class LeaderMap : ClassMap<Leader>
{
public LeaderMap()
{
Map(m => m.LongColumn6).Index(5); // the column that cause the issue
//complete the List
Map(m => m.Category).Index(2);
Map(m => m.StockCode).Index(11);
Map(m => m.Cost).Index(7);
Map(m => m.Description).Index(4);
}
}
那么阅读就简单了:
using (var csvReader = new CsvReader(reader, CultureInfo.InvariantCulture ))
{
csvReader.Configuration.HasHeaderRecord = false;
csvReader.Configuration.RegisterClassMap<LeaderMap>();
records = csvReader.GetRecords<Leader>().ToList();
}
请注意,在这个 live demo 中。
我使用 StringReader 来模拟文件 Reader.
您可以使用文件 reader 并将其传递给您的路径。
我已经查看了我能找到的所有 csv 阅读示例,但我不太确定我哪里出错了。
我对 C# 还很陌生,但到目前为止我很喜欢它!
无论如何,这里的代码在 大多数 的时候都很好用(你可以从评论中看到我在阅读中尝试了很多不同的选项):
StreamReader sr = new StreamReader(csvFileToImport);
while (sr.EndOfStream != true)
{
string line = sr.ReadLine();
//string[] value = line.Split(new string[] { "\",\"" }, StringSplitOptions.None);
//string[] value = line.Split(new string[] {","}, StringSplitOptions.None);
//string[] value = line.Split(new string[] { "(?=(?:[^']*'[^']*')*[^']*$)" }, StringSplitOptions.None);
//string[] value = line.Split(new string[] { "," }, StringSplitOptions.None);
string[] value = Regex.Split(line, @"\s|[,]");
StockItem si = new StockItem();
switch (stockFile.Supplier)
{
case "Leader":
si.Supplier = stockFile.Supplier;
si.Category = value[2].Replace("'", "''");
si.StockCode = value[11].Replace("'", "''");
si.Cost = Convert.ToDecimal(value[7]);
si.Description = value[4].Replace("'", "''");
si.Image = value[9].Replace("'", "''");
si.Manufacturer = value[10].Replace("'", "''");
si.Sell = Convert.ToDecimal(value[8]);
si.StockAdelaide = value[17].Replace("'", "''");
si.StockBrisbane = value[18].Replace("'", "''");
si.StockMelbourne = value[19].Replace("'", "''");
si.StockPerth = value[20].Replace("'", "''");
si.StockSydney = value[21].Replace("'", "''");
si.Subcategory = value[3].Replace("'", "''");
//Add line into db
string sql = "insert into Stock (Supplier, StockCode, Manufacturer, Category, Subcategory, Description, Cost, Sell, Image, StockPerth, StockAdelaide, StockSydney, StockBrisbane, StockMelbourne) values ('" + si.Supplier + "', '" + si.StockCode + "', '" + si.Manufacturer + "', '" + si.Category + "', '" + si.Subcategory + "', '" + si.Description + "', " + si.Cost + ", " + si.Sell + ", '" + si.Image + "', '" + si.StockPerth + "', '" + si.StockAdelaide + "', '" + si.StockSydney + "', '" + si.StockBrisbane + "', '" + si.StockMelbourne + "')";
cmd = new SqlCommand(sql, cn);
cmd.ExecuteNonQuery();
break;
default:
break;
}
}
success = true;
cn.Close();
我已经链接到一个 1 行的 csv 文件,如果有人愿意看一下,我将不胜感激!
提前致谢,也请随时指出我可以改进的任何通用代码...我相信还有很多地方需要改进。
再次感谢:)
CSV Link: https://www.dropbox.com/s/nnaruu0twds3wrl/csv_error.csv?dl=0
更新:
很抱歉不够清晰,因为我在阅读文件时收到以下错误:
System.FormatException: 'Input string was not in a correct format.'
该行内容如下:
"MECMD4VL2X426,ME,Memory,DDR-4 (Desktop),Corsair Vengeance LPX 8GB (2x4GB) DDR4 2666MHz C16 Desktop Gaming Memory Black,\"Corsair 8GB (2x4GB) DDR4 2666MHz Vengeance LPX Black"
当我查询数组时,它显示的值为:
value[0] "MECMD4VL2X426"
value[1] "ME"
value[2] "Memory"
value[3] "DDR-4"
value[4] "(Desktop)"
value[5] "Corsair"
value[6] "Vengeance"
value[7] "LPX"
...
它似乎卡在括号中(应该读入值 [3]),然后开始在 space 而不是逗号上分隔。
如果需要,我很乐意使用第 3 方 csv reader,但是我很想自己了解它是如何工作的。
读取您使用 string line = sr.ReadLine();
但 RFC 4180 的 csv,
2.6 告诉我们一个包含多行的字段应该用DQuote封装 "
.
因此,如果您的文档中存在这些多行字段,则逐行读取文件将是一个问题。
我会放弃手工制作的正则表达式和 ReadLine
并使用更强大的解析器,如 CSV Helper.
然后定义要从 CSV 中获取的对象。
public class Leader
{
public string LongColumn6 { get; set; }
public string Supplier { get; set; }
public string Category { get; set; }
public string StockCode { get; set; }
public Decimal Cost { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public string Manufacturer { get; set; }
public Decimal Sell { get; set; }
public string StockAdelaide { get; set; }
public string StockBrisbane { get; set; }
public string StockMelbourne { get; set; }
public string StockPerth { get; set; }
public string StockSydney { get; set; }
public string Subcategory { get; set; }
}
它是各自的映射器:列 & 是 Foo 属性等。
public sealed class LeaderMap : ClassMap<Leader>
{
public LeaderMap()
{
Map(m => m.LongColumn6).Index(5); // the column that cause the issue
//complete the List
Map(m => m.Category).Index(2);
Map(m => m.StockCode).Index(11);
Map(m => m.Cost).Index(7);
Map(m => m.Description).Index(4);
}
}
那么阅读就简单了:
using (var csvReader = new CsvReader(reader, CultureInfo.InvariantCulture ))
{
csvReader.Configuration.HasHeaderRecord = false;
csvReader.Configuration.RegisterClassMap<LeaderMap>();
records = csvReader.GetRecords<Leader>().ToList();
}
请注意,在这个 live demo 中。
我使用 StringReader 来模拟文件 Reader.
您可以使用文件 reader 并将其传递给您的路径。