【问题标题】:Reading/writing CSV/tab delimited files in c#在 C# 中读取/写入 CSV/制表符分隔的文件
【发布时间】:2018-11-04 03:47:29
【问题描述】:

我需要从 CSV/制表符分隔的文件中读取,并从 .net 中写入这样的文件。

难点是不知道每个文件的结构,需要将cvs/tab文件写入数据表,FileHelpers库好像不支持。

我已经使用 OLEDB 为 Excel 编写了它,但真的找不到为此编写选项卡文件的方法,所以将返回到库。

任何人都可以提供建议吗?

【问题讨论】:

    标签: c# csv


    【解决方案1】:

    .NET 带有一个名为 TextFieldParser 类的 CSV/tab 分隔文件解析器。

    http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.fileio.textfieldparser.aspx

    它支持 CSV 文件的完整 RFC 和非常好的错误报告。

    【讨论】:

    • 您必须喜欢 Microsoft.VisualBasic.dll 中的通用实用程序类。
    • 不幸的是,这似乎不支持指定您自己的文本换行字符,它假定这是一个双引号,只允许您打开/关闭。
    • 你能提供一个简单的例子吗?链接是不够的答案。如果它破坏了这个响应对任何谷歌人来说都是无用的。
    【解决方案2】:

    我用过这个CsvReader,它真的很棒而且可配置性很好。它在字符串和分隔符的各种转义中表现良好。其他快速和肮脏的实现中的转义很差,但是这个库非常适合阅读。如果需要,您还可以通过一些额外的代码行添加缓存。

    不支持编写,但自己实现相当简单。或者通过this code 激发自己。

    【讨论】:

    • 对不起.. 这对我来说有点遥远,但我想我在编写 csv 文件时主要考虑的是分隔字符串(我已经有一段时间没有编写 csv 文件了)。
    • 我添加了一个CSV写入的链接,你可以用你喜欢的分隔符替换一些常量字符串,应该没问题。阅读远比写作复杂...
    • 但是编写包含任意字符串的 CSV 文件并非易事。记住转义序列!
    • 为什么你会推荐这个而不是 .NET 自带的那个?
    【解决方案3】:

    使用 CsvHelper 的简单示例

    using (TextWriter writer = new StreamWriter(filePath)
    {
        var csvWriter = new CsvWriter(writer);
        csvWriter.Configuration.Delimiter = "\t";
        csvWriter.Configuration.Encoding = Encoding.UTF8;
        csvWriter.WriteRecords(exportRecords); 
    }
    

    【讨论】:

      【解决方案4】:

      这里有几个 CSV 阅读器实现:

      http://www.codeproject.com/KB/database/CsvReader.aspx

      http://www.heikniemi.fi/jhlib/(只是库的一部分;也包括 CSV 写入器)

      我怀疑是否有“自动”将 CSV 转换为 DataTable 或数据库的标准方法,您必须编写代码才能做到这一点。如何做到这一点是一个单独的问题。

      【讨论】:

        【解决方案5】:

        您将在代码中创建数据表,并且(假设是标题行)可以根据文件中的第一行创建列。之后,只需读取文件并根据其中的数据创建新行。

        你可以这样使用:

        DataTable Tbl = new DataTable();
        using(StreamReader sr = new StreamReader(path))
        {
          int count = 0;
          string headerRow = sr.Read();
          string[] headers = headerRow.split("\t") //Or ","
          foreach(string h in headers)
          {
            DataColumn dc = new DataColumn(h);
            Tbl.Columns.Add(dc);
            count++;
          }
          while(sr.Peek())
          {
            string data = sr.Read();
            string[] cells = data.Split("\t") 
            DataRow row = new DataRow();
            foreach(string c in cells)
            {
              row.Columns.Add(c);
            }
            Tbl.Rows.Add(row);
          }
        }
        

        上面的代码还没有编译,所以可能有一些错误,但它应该能让你走上正轨。

        【讨论】:

        • 您的拆分代码错误,因为您可能在带引号的字符串中有分隔符。
        • @Jonathan Allen:是的,确实可以。它并非旨在成为完整的解决方案......只是指向可能的正确轨道的指针。
        • 使用您的代码时出现错误。 'while(sr.Peek())' 行抛出错误“无法将类型 'int' 隐式转换为 'bool'”我很困惑。我认为整数值 0 在布尔值中计算为假,而所有其他整数值计算为真?自编写以来,C# 语法是否发生了变化?
        【解决方案6】:

        您可以读取和写入 csv 文件.. 这可能对您有帮助。

        将拆分字符传递给此参数“serparationChar”

        例子:-

            private DataTable dataTable = null;
            private bool IsHeader = true;
            private string headerLine = string.Empty;
            private List<string> AllLines = new List<string>();
            private StringBuilder sb = new StringBuilder();
            private char seprateChar = ',';
        
        
            public DataTable ReadCSV(string path, bool IsReadHeader, char serparationChar)
            {
                seprateChar = serparationChar;
                IsHeader = IsReadHeader;
                using (StreamReader sr = new StreamReader(path,Encoding.Default))
                {
                    while (!sr.EndOfStream)
                    {
                      AllLines.Add( sr.ReadLine());
                    }
                    createTemplate(AllLines);
                }
        
                return dataTable;
            }
            public void WriteCSV(string path,DataTable dtable,char serparationChar)
            {
                AllLines = new List<string>();
                seprateChar = serparationChar;
                List<string> StableHeadrs = new List<string>();
                int colCount = 0;
                using (StreamWriter sw = new StreamWriter(path))
                {
                    foreach (DataColumn col in dtable.Columns)
                    {
                        sb.Append(col.ColumnName);
                        if(dataTable.Columns.Count-1 > colCount)
                        sb.Append(seprateChar);
                        colCount++;
                    }
                    AllLines.Add(sb.ToString());
        
                    for (int i = 0; i < dtable.Rows.Count; i++)
                    {
                        sb.Clear();
                        for (int j = 0; j < dtable.Columns.Count; j++)
                        {
                            sb.Append(Convert.ToString(dtable.Rows[i][j]));
                            if (dataTable.Columns.Count - 1 > j)
                            sb.Append(seprateChar);
                        }
                        AllLines.Add(sb.ToString());
                    }
        
                    foreach (string dataline in AllLines)
                    {
                        sw.WriteLine(dataline);
                    }
                }
        
        
            }
        
            private DataTable createTemplate(List<string> lines)
            {
        
                List<string> headers = new List<string>();
                dataTable = new DataTable();
                if (lines.Count > 0)
                {
                    string[] argHeaders = null;
                    for (int i = 0; i < lines.Count; i++)
                    {
                        if (i > 0)
                        {
                            DataRow newRow = dataTable.NewRow();
                            // others add to rows
                            string[] argLines = lines[i].Split(seprateChar);
                            for (int b = 0; b < argLines.Length; b++)
                            {
                                newRow[b] = argLines[b];
                            }
                            dataTable.Rows.Add(newRow);
        
                        }
                        else
                        {
                            // header add to columns
                            argHeaders = lines[0].Split(seprateChar);
                            foreach (string c in argHeaders)
                            {
                                DataColumn column = new DataColumn(c, typeof(string));
                                dataTable.Columns.Add(column);
                            }
                        }
        
                    }
        
                }
                return dataTable;
            }
        

        【讨论】:

          【解决方案7】:

          我找到了最好的解决方案

          http://www.codeproject.com/Articles/415732/Reading-and-Writing-CSV-Files-in-Csharp

          只是我不得不重写

          void ReadTest()
          {
              // Read sample data from CSV file
              using (CsvFileReader reader = new CsvFileReader("ReadTest.csv"))
              {
                  CsvRow row = new CsvRow();
                  while (reader.ReadRow(row))
                  {
                      foreach (string s in row)
                      {
                          Console.Write(s);
                          Console.Write(" ");
                      }
                      Console.WriteLine();
          
                      row = new CsvRow(); //this line added
                  }
              }
          }
          

          【讨论】:

            【解决方案8】:

            嗯,还有另一个库 Cinchoo ETL - 一个开源库,用于读取和写入 CSV 文件。

            读取 CSV 文件的几种方法

            Id, Name
            1, Tom
            2, Mark
            

            这就是你如何使用这个库来阅读它

            using (var reader = new ChoCSVReader("emp.csv").WithFirstLineHeader())
            {
               foreach (dynamic item in reader)
               {
                  Console.WriteLine(item.Id);
                  Console.WriteLine(item.Name);
               }
            }
            

            如果您定义了 POCO 对象以匹配 CSV 文件,如下所示

            public class Employee
            {
               public int Id { get; set; }
               public string Name { get; set; }
            }
            

            您可以使用下面的这个 POCO 类解析相同的文件

            using (var reader = new ChoCSVReader<Employee>("emp.csv").WithFirstLineHeader())
            {
               foreach (var item in reader)
               {
                  Console.WriteLine(item.Id);
                  Console.WriteLine(item.Name);
               }
            }
            

            请查看CodeProject的文章了解如何使用它。

            免责声明:我是这个库的作者

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2015-10-15
              • 2020-06-18
              • 1970-01-01
              • 2023-03-10
              • 2013-11-28
              • 2016-12-09
              • 1970-01-01
              相关资源
              最近更新 更多