【问题标题】:C# StreamRead in CSV file with a field containing ","CSV 文件中的 C# StreamRead,其中包含“,”的字段
【发布时间】:2016-06-02 11:26:19
【问题描述】:

我在封闭的环境中工作,我无法安装额外的包并且使用 .Net 框架类的能力有限。另外,我无法控制收到的 CSV 文件格式。

我收到一个 CSV 文件,必须将其拉入我们的业务系统并更新数据库。

我可以通过以下代码将文件拉入 DataTable ...

CSV File Ex:
Order#     Qty       Description                             ...
12345      3         desc1, desc2, desc3, etc..


while (!sr.EndOfStream)
{
    string[] rows = sr.ReadLine().Split(',');

    DataRow dr = dt.NewRow();
    for (int i = 0; i < rows.Length; i++)
    {
        dr[i] = rows[i];
    }
    dt.Rows.Add(dr);
}

但是,问题在于 CSV 文件中的一个字段是包含多个“,”字符的描述。执行上述操作会将描述值中的每个逗号分隔的单词集加载到行数组中自己的索引中。

目前 csv 文件中应该总共有 10 列,但是对于描述字段问题,列数会根据描述字段中逗号的长度/数量而有所不同...10、15、22 列等。

在发送 CSV 文件之前,我无法控制它的格式。有什么办法可以解决这个问题。即使在创建 DataTable 时跳过该字段也可以满足我的目的。

谢谢

【问题讨论】:

  • 使用 CsvHelper。 nuget.org/packages/CsvHelper
  • 不要自己写CSV解析代码,用库吧。
  • @PranavPatel 该解决方案假定 CSV 数据中的逗号已转义。 OP 提到他无法控制输入。
  • 如果列总是有一个TAB,然后尝试用string[] rows = sr.ReadLine().Split('\t');分割它

标签: c# csv datatable streamreader


【解决方案1】:

您可以使用 textqualifier 将每个字段括起来,这样逗号或分号就不会被视为分隔符。以下方法应该可以解决问题。

安装包 CsvHelper

 public static DataTable ReadCSVToDataTable(string path)
    {
        CsvHelper.Configuration.CsvConfiguration config = new CsvHelper.Configuration.CsvConfiguration();
        config.Delimiter = delimeter;
        config.Encoding = new UTF8Encoding(false);
        if (string.IsNullOrEmpty(textQualifier))
        {
            config.QuoteAllFields = false;
        }
        else
        {
            char qualifier = textQualifier.ToCharArray()[0];
            config.Quote = qualifier;
            config.QuoteAllFields = true;
        }
        DataTable dt = new DataTable();
        using (var sr = new StreamReader(path))
        {
            using (var reader = new CsvReader(sr, config))
            {
                int j = 0;
                while (reader.Read())
                {
                    if (j == 0)
                    {
                        if (config.HasHeaderRecord)
                        {
                            foreach (string header in reader.FieldHeaders)
                                dt.Columns.Add(header);
                        }
                        else
                        {
                            for (int i = 0; i < reader.CurrentRecord.Length; i++)
                                dt.Columns.Add();
                        }
                        j++;
                    }
                    AddRow(dt, reader);
                }
            }

        }
        return dt;
    }

【讨论】:

    【解决方案2】:

    Fstagger,这应该对您有用,假设您只有一列带有内部逗号并且 CSV 格式正确(特别是如果描述字段以“”开头并以“,”结尾。您需要将我的示例 INDEX_OF_DESCRIPTION 替换为实际价值。

    int iDescStart = 0;
    int iDescEnd = 0;
    string zLine = "";
    
    const int INDEX_OF_DESCRIPTION = 3;
    const char SEPARATOR   = '\u001F';  //ASCII Unit Separator, decimal 31
    
    while(!sr.EndOfStream){
       zLine = sr.ReadLine();
    
       iDescStart = zLine.IndexOf(",\"");
       iDescEnd = zLine.IndexOf("\",");
       zLine = zLine.Substring(0, iDescStart)
             + ","
             + zLine.Substring(iDescStart + 2, iDescEnd - iDescStart - 2).Replace(',', SEPARATOR)
             + ","
             + zLine.Substring(iDescEnd + 2);
       string[] zaFields = zLine.Split(',');
       zaFields[INDEX_OF_DESCRIPTION] = zaFields[INDEX_OF_DESCRIPTION].Replace(SEPARATOR, ',');
    
       datarow dr = dt.NewRow();
       for (int i = 0; i < zaFields.Length; i++){
          dr[i] = zaFields[i];
       }
       dt.Rows.Add(dr);
    }
    

    让我知道这是否适合你:)

    【讨论】:

    • 谢谢迈克尔......我搞砸了更多,并想出了我自己的解决方法。我没有尝试代码,但我确信它会产生相同的结果。再次感谢!
    【解决方案3】:

    您的 CSV 似乎有固定大小的列,其中填充了空格。所以我想你最好为每列读取固定数量的字符并修剪尾随空格,而不是用逗号分隔。

    【讨论】:

      【解决方案4】:

      试试this 类。 它处理您需要的逗号。

      【讨论】:

      • 不幸的是,我们使用的 ERP 软件不允许我们安装/引用外部程序集。制表符分隔的拆分不起作用,它作为一行出现。 CSV 在描述字段周围有“”...即“desc1,desc2”是否有某种方法可以在拆分方法中识别和转义“”?
      • ERP 甚至不允许使用 .net Framework 类吗?
      • 是的,我们可以使用 .Net 框架类,但是让它正常工作很痛苦。从可维护性的角度来看,这对我们来说不值得。
      【解决方案5】:

      我的解决方案最终奏效了

      while (!sr.EndOfStream)
      {                      
          string[] rows = sr.ReadLine().Split(',');
          var fullrow = String.Empty;
      
          foreach (var entry in rows)
          {
              fullrow += entry.ToString() + ",";
          }
      
          var startQuote = fullrow.IndexOf("\"");
          var endQuote = fullrow.IndexOf("\"", startQuote + 1); //LastIndexOf("\"");
      
          if (startQuote > -1 && endQuote > -1)
          {    
              var substring = fullrow.Substring(startQuote, Math.Abs(startQuote - endQuote));
              substring = substring.Replace(',', ' ');
              fullrow = fullrow.Remove(startQuote, Math.Abs(startQuote - endQuote)).Insert(startQuote, substring);
          }
      
          rows = fullrow.Split(',');       
      
          DataRow dr = dt.NewRow();
          for (int i = 0; i < rows.Length; i++)
          {
              dr[i] = rows[i];
          }
          dt.Rows.Add(dr);
      }
      

      感谢@Michael Gorsich 提供备用代码!

      【讨论】:

        猜你喜欢
        • 2011-10-24
        • 1970-01-01
        • 2019-10-31
        • 1970-01-01
        • 1970-01-01
        • 2017-10-10
        • 2016-05-08
        • 2021-06-16
        • 1970-01-01
        相关资源
        最近更新 更多