【问题标题】:How to create CSV Excel file C#? [closed]如何创建 CSV Excel 文件 C#? [关闭]
【发布时间】:2011-01-26 04:54:49
【问题描述】:

我正在寻找用于创建 CSV Excel 文件的课程。

预期功能:

  • 使用极其简单
  • 转义逗号和引号,以便 Excel 处理好
  • 以防时区格式导出日期和日期时间

你知道有什么职业可以做到这一点吗?

【问题讨论】:

  • 最好在 QUESTION 部分提出问题,然后在 ANSWER 部分发布您自己的答案。请务必在问题中添加标签和关键字以使其可搜索。
  • 重要提示:当“值”中有回车时,您还应该添加引号。
  • 谢谢@Chris,如果可以的话,给个建议吧,这段代码可能会抛出 KeyNotFoundException,请看我的回答。
  • 它最好的例子...但是我如何在单个文件中添加两个表,这意味着我有一个两行的表,另一个表是 10 行,并且都有唯一的列名。我想在顶部添加两行表格,在两行间隙之后我想添加第二个表格。

标签: c# excel csv export


【解决方案1】:

我使用反射编写的版本略有不同以满足我的需要。我必须将对象列表导出到 csv。以防将来有人想使用它。

public class CsvExport<T> where T: class
    {
        public List<T> Objects;

        public CsvExport(List<T> objects)
        {
            Objects = objects;
        }

        public string Export()
        {
            return Export(true);
        }

        public string Export(bool includeHeaderLine)
        {

            StringBuilder sb = new StringBuilder();
            //Get properties using reflection.
            IList<PropertyInfo> propertyInfos = typeof(T).GetProperties();

            if (includeHeaderLine)
            {
                //add header line.
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    sb.Append(propertyInfo.Name).Append(",");
                }
                sb.Remove(sb.Length - 1, 1).AppendLine();
            }

            //add value for each property.
            foreach (T obj in Objects)
            {               
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    sb.Append(MakeValueCsvFriendly(propertyInfo.GetValue(obj, null))).Append(",");
                }
                sb.Remove(sb.Length - 1, 1).AppendLine();
            }

            return sb.ToString();
        }

        //export to a file.
        public void ExportToFile(string path)
        {
            File.WriteAllText(path, Export());
        }

        //export as binary data.
        public byte[] ExportToBytes()
        {
            return Encoding.UTF8.GetBytes(Export());
        }

        //get the csv value for field.
        private string MakeValueCsvFriendly(object value)
        {
            if (value == null) return "";
            if (value is Nullable && ((INullable)value).IsNull) return "";

            if (value is DateTime)
            {
                if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
                    return ((DateTime)value).ToString("yyyy-MM-dd");
                return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
            }
            string output = value.ToString();

            if (output.Contains(",") || output.Contains("\""))
                output = '"' + output.Replace("\"", "\"\"") + '"';

            return output;

        }
    }

使用示例:(根据评论更新)

CsvExport<BusinessObject> csv= new CsvExport<BusinessObject>(GetBusinessObjectList());
Response.Write(csv.Export());

【讨论】:

  • 更像是这样:List x= new List(); CsvExport x = new CsvExport(MUsers);
  • 你的INullable接口是从哪里来的?
  • 它最好的例子...但是我如何在单个文件中添加两个表,这意味着我有一个两行的表,另一个表是 10 行,并且都有唯一的列名。我想在顶部添加两行表格,在两行间隙之后我想添加第二个表格。
  • 我知道原来的帖子是 2011 年的,所以我不确定在当时使用的 .NET 版本中是否可行。但是为什么不去掉public string Export()方法,把另一个方法改成public string Export(bool includeHeaderLiner = true)(带默认参数值)。同样,我不确定默认参数是否在 2011 年可用,但当前的代码在我看来只是正统的。
【解决方案2】:

请原谅我

但我认为公共开源存储库是共享代码和做出贡献、更正和添加诸如“我修复了这个,我修复了那个”之类的更好方式

所以我用 topic-starter 的代码和所有的补充做了一个简单的 git-repository:

https://github.com/jitbit/CsvExport

我自己也添加了一些有用的修复。每个人都可以添加建议,将其分叉以做出贡献等等等。将您的分叉发送给我,以便我将它们合并回存储库。

PS。我为克里斯发布了所有版权声明。 @Chris 如果你反对这个想法 - 告诉我,我会杀了它。

【讨论】:

    【解决方案3】:

    另一个读写 CSV 文件的好方法是filehelpers(开源)。

    【讨论】:

    • NB:Excel support is only for basic scenarios:目前实现的Excel支持只针对基本场景。如果您需要自定义格式、图表等,您必须使用自定义代码。强烈建议直接使用 NPOI 库
    【解决方案4】:

    使用 string.Join 代替所有的 foreach 循环怎么样?

    【讨论】:

    • String.Join 仅适用于 string[],而我正在使用 List 的一些功能。
    • String.Join("," , List&lt;string&gt;) 也可以。
    【解决方案5】:

    如果有人愿意,我将其转换为 IEnumerable 上的扩展方法:

    public static class ListExtensions
    {
        public static string ExportAsCSV<T>(this IEnumerable<T> listToExport, bool includeHeaderLine, string delimeter)
        {
            StringBuilder sb = new StringBuilder();
    
            IList<PropertyInfo> propertyInfos = typeof(T).GetProperties();
    
            if (includeHeaderLine)
            {
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    sb.Append(propertyInfo.Name).Append(",");
                }
                sb.Remove(sb.Length - 1, 1).AppendLine();
            }
    
            foreach (T obj in listToExport)
            {
                T localObject = obj;
    
                var line = String.Join(delimeter, propertyInfos.Select(x => SanitizeValuesForCSV(x.GetValue(localObject, null), delimeter)));
    
                sb.AppendLine(line);
            }
    
            return sb.ToString();
        }
    
        private static string SanitizeValuesForCSV(object value, string delimeter)
        {
            string output;
    
            if (value == null) return "";
    
            if (value is DateTime)
            {
                output = ((DateTime)value).ToLongDateString();
            }
            else
            {
                output = value.ToString();                
            }
    
            if (output.Contains(delimeter) || output.Contains("\""))
                output = '"' + output.Replace("\"", "\"\"") + '"';
    
            output = output.Replace("\n", " ");
            output = output.Replace("\r", "");
    
            return output;
        }
    }
    

    【讨论】:

      【解决方案6】:

      这门课做得很好。简单易用。我修改了类以在导出的第一行中包含一个标题;想我会分享:

      使用:

      CsvExport myExport = new CsvExport();
      myExport.addTitle = String.Format("Name: {0},{1}", lastName, firstName));
      

      类:

      public class CsvExport
      {
          List<string> fields = new List<string>();
      
          public string addTitle { get; set; } // string for the first row of the export
      
          List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
          Dictionary<string, object> currentRow
          {
              get
              {
                  return rows[rows.Count - 1];
              }
          }
      
          public object this[string field]
          {
              set
              {
                  if (!fields.Contains(field)) fields.Add(field);
                  currentRow[field] = value;
              }
          }
      
          public void AddRow()
          {
              rows.Add(new Dictionary<string, object>());
          }
      
          string MakeValueCsvFriendly(object value)
          {
              if (value == null) return "";
              if (value is Nullable && ((INullable)value).IsNull) return "";
              if (value is DateTime)
              {
                  if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
                      return ((DateTime)value).ToString("yyyy-MM-dd");
                  return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
              }
              string output = value.ToString();
              if (output.Contains(",") || output.Contains("\""))
                  output = '"' + output.Replace("\"", "\"\"") + '"';
              return output;
      
          }
      
          public string Export()
          {
              StringBuilder sb = new StringBuilder();
      
              // if there is a title
              if (!string.IsNullOrEmpty(addTitle))
              {
                  // escape chars that would otherwise break the row / export
                  char[] csvTokens = new[] { '\"', ',', '\n', '\r' };
      
                  if (addTitle.IndexOfAny(csvTokens) >= 0)
                  {
                      addTitle = "\"" + addTitle.Replace("\"", "\"\"") + "\"";
                  }
                  sb.Append(addTitle).Append(",");
                  sb.AppendLine();
              }
      
      
              // The header
              foreach (string field in fields)
              sb.Append(field).Append(",");
              sb.AppendLine();
      
              // The rows
              foreach (Dictionary<string, object> row in rows)
              {
                  foreach (string field in fields)
                      sb.Append(MakeValueCsvFriendly(row[field])).Append(",");
                  sb.AppendLine();
              }
      
              return sb.ToString();
          }
      
          public void ExportToFile(string path)
          {
              File.WriteAllText(path, Export());
          }
      
          public byte[] ExportToBytes()
          {
              return Encoding.UTF8.GetBytes(Export());
          }
      }
      

      【讨论】:

        【解决方案7】:

        有一个用于 CSV 的开源库,您可以使用 nuget 获得它:http://joshclose.github.io/CsvHelper/

        【讨论】:

          【解决方案8】:

          我添加了 ExportToStream,因此 csv 不必先保存到硬盘。

          public Stream ExportToStream()
          {
              MemoryStream stream = new MemoryStream();
              StreamWriter writer = new StreamWriter(stream);
              writer.Write(Export(true));
              writer.Flush();
              stream.Position = 0;
              return stream;
          }
          

          【讨论】:

            【解决方案9】:

            我已经添加了

            public void ExportToFile(string path, DataTable tabela)
            {
            
                 DataColumnCollection colunas = tabela.Columns;
            
                 foreach (DataRow linha in tabela.Rows)
                 {
            
                       this.AddRow();
            
                       foreach (DataColumn coluna in colunas)
            
                       {
            
                           this[coluna.ColumnName] = linha[coluna];
            
                       }
            
                  }
                  this.ExportToFile(path);
            
            }
            

            以前的代码不适用于旧的 .NET 版本。对于 3.5 版本的框架,请使用其他版本:

                    public void ExportToFile(string path)
                {
                    bool abort = false;
                    bool exists = false;
                    do
                    {
                        exists = File.Exists(path);
                        if (!exists)
                        {
                            if( !Convert.ToBoolean( File.CreateText(path) ) )
                                    abort = true;
                        }
                    } while (!exists || abort);
            
                    if (!abort)
                    {
                        //File.OpenWrite(path);
                        using (StreamWriter w = File.AppendText(path))
                        {
                            w.WriteLine("hello");
                        }
            
                    }
            
                    //File.WriteAllText(path, Export());
                }
            

            【讨论】:

              【解决方案10】:

              非常感谢! 我将课程修改为:

              • 使用变量分隔符,而不是在代码中硬编码
              • 全部替换 MakeValueCsvFriendly 中的新行 (\n \r \n\r)

              代码:

              using System;
              using System.Collections.Generic;
              using System.Linq;
              using System.Data.SqlTypes;
              using System.IO;
              using System.Text;
              using System.Text.RegularExpressions;
              
                  public class CsvExport
                  {
              
                      public char delim = ';';
                      /// <summary>
                      /// To keep the ordered list of column names
                      /// </summary>
                      List<string> fields = new List<string>();
              
                      /// <summary>
                      /// The list of rows
                      /// </summary>
                      List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
              
                      /// <summary>
                      /// The current row
                      /// </summary>
                      Dictionary<string, object> currentRow { get { return rows[rows.Count - 1]; } }
              
                      /// <summary>
                      /// Set a value on this column
                      /// </summary>
                      public object this[string field]
                      {
                          set
                          {
                              // Keep track of the field names, because the dictionary loses the ordering
                              if (!fields.Contains(field)) fields.Add(field);
                              currentRow[field] = value;
                          }
                      }
              
                      /// <summary>
                      /// Call this before setting any fields on a row
                      /// </summary>
                      public void AddRow()
                      {
                          rows.Add(new Dictionary<string, object>());
                      }
              
                      /// <summary>
                      /// Converts a value to how it should output in a csv file
                      /// If it has a comma, it needs surrounding with double quotes
                      /// Eg Sydney, Australia -> "Sydney, Australia"
                      /// Also if it contains any double quotes ("), then they need to be replaced with quad quotes[sic] ("")
                      /// Eg "Dangerous Dan" McGrew -> """Dangerous Dan"" McGrew"
                      /// </summary>
                      string MakeValueCsvFriendly(object value)
                      {
                          if (value == null) return "";
                          if (value is INullable && ((INullable)value).IsNull) return "";
                          if (value is DateTime)
                          {
                              if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
                                  return ((DateTime)value).ToString("yyyy-MM-dd");
                              return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
                          }
                          string output = value.ToString();
                          if (output.Contains(delim) || output.Contains("\""))
                              output = '"' + output.Replace("\"", "\"\"") + '"';
                          if (Regex.IsMatch(output,  @"(?:\r\n|\n|\r)"))
                              output = string.Join(" ", Regex.Split(output, @"(?:\r\n|\n|\r)"));
                          return output;
                      }
              
                      /// <summary>
                      /// Output all rows as a CSV returning a string
                      /// </summary>
                      public string Export()
                      {
                          StringBuilder sb = new StringBuilder();
              
                          // The header
                          foreach (string field in fields)
                              sb.Append(field).Append(delim);
                          sb.AppendLine();
              
                          // The rows
                          foreach (Dictionary<string, object> row in rows)
                          {
                              foreach (string field in fields)
                                  sb.Append(MakeValueCsvFriendly(row[field])).Append(delim);
                              sb.AppendLine();
                          }
              
                          return sb.ToString();
                      }
              
                      /// <summary>
                      /// Exports to a file
                      /// </summary>
                      public void ExportToFile(string path)
                      {
                          File.WriteAllText(path, Export());
                      }
              
                      /// <summary>
                      /// Exports as raw UTF8 bytes
                      /// </summary>
                      public byte[] ExportToBytes()
                      {
                          return Encoding.UTF8.GetBytes(Export());
              
                      }
              
                  }
              

              【讨论】:

                【解决方案11】:

                您也可以使用 ADO 来执行此操作:http://weblogs.asp.net/fmarguerie/archive/2003/10/01/29964.aspx

                【讨论】:

                  【解决方案12】:

                  原来的类有一个问题,就是如果你想添加一个新的列,你会在Export方法上收到KeyNotFoundException。例如:

                  static void Main(string[] args)
                  {
                      var export = new CsvExport();
                  
                      export.AddRow();
                      export["Region"] = "New York, USA";
                      export["Sales"] = 100000;
                      export["Date Opened"] = new DateTime(2003, 12, 31);
                  
                      export.AddRow();
                      export["Region"] = "Sydney \"in\" Australia";
                      export["Sales"] = 50000;
                      export["Date Opened"] = new DateTime(2005, 1, 1, 9, 30, 0);
                      export["Balance"] = 3.45f;  //Exception is throwed for this new column
                  
                      export.ExportToFile("Somefile.csv");
                  }
                  

                  为了解决这个问题,并利用@KeyboardCowboy 使用反射的思想,我修改了代码以允许添加不具有相同列的行。您可以使用匿名类的实例。例如:

                  static void Main(string[] args)
                  {
                      var export = new CsvExporter();
                  
                      export.AddRow(new {A = 12, B = "Empty"});
                      export.AddRow(new {A = 34.5f, D = false});
                  
                      export.ExportToFile("File.csv");
                  }
                  

                  你可以在这里CsvExporter下载源代码。随意使用和修改。

                  现在,如果您要写入的所有行都属于同一类,我创建了通用类 CsvWriter.cs,它具有更好的 RAM 使用性能,非常适合写入大文件。此外,它还允许您向数据添加格式化程序你想要的类型。使用示例:

                  class Program
                  {
                      static void Main(string[] args)
                      {
                          var writer = new CsvWriter<Person>("Persons.csv");
                  
                          writer.AddFormatter<DateTime>(d => d.ToString("MM/dd/yyyy"));
                  
                          writer.WriteHeaders();
                          writer.WriteRows(GetPersons());
                  
                          writer.Flush();
                          writer.Close();
                      }
                  
                      private static IEnumerable<Person> GetPersons()
                      {
                          yield return new Person
                              {
                                  FirstName = "Jhon", 
                                  LastName = "Doe", 
                                  Sex = 'M'
                              };
                  
                          yield return new Person
                              {
                                  FirstName = "Jhane", 
                                  LastName = "Doe",
                                  Sex = 'F',
                                  BirthDate = DateTime.Now
                              };
                          }
                      }
                  
                  
                      class Person
                      {
                          public string FirstName { get; set; }
                  
                          public string LastName { get; set; }
                  
                          public char Sex  { get; set; }
                  
                          public DateTime BirthDate { get; set; }
                      }
                  

                  【讨论】:

                    【解决方案13】:

                    您只需要 1 个函数即可执行此操作。 您只需在解决方案资源管理器中创建一个文件夹并将 csv 文件存储在那里,然后将该文件导出给用户。

                    就我而言,我有一个文件夹下载。首先,我将所有内容导出到该目录,然后将其导出给用户。对于 response.end 处理,我使用了 ThreadAbortException。因此,在我的解决方案中,它是 100% 真实且有效的功能。

                    protected void lnkExport_OnClick(object sender, EventArgs e)
                    {
                    
                        string filename = strFileName = "Export.csv";
                    
                        DataTable dt = obj.GetData();  
                    
                    // call the content and load it into the datatable
                    
                        strFileName = Server.MapPath("Downloads") + "\\" + strFileName;
                    
                    // creating a file in the downloads folder in your solution explorer
                    
                        TextWriter tw = new StreamWriter(strFileName);
                    
                    // using the built in class textwriter for writing your content in the exporting file
                    
                        string strData = "Username,Password,City";
                    
                    // above line is the header for your exported file. So add headings for your coloumns in excel(.csv) file and seperate them with ","
                    
                        strData += Environment.NewLine;
                    
                    // setting the environment to the new line
                    
                        foreach (DataRow dr in dt.Rows)
                        {
                           strData += dr["Username"].ToString() + "," + dr["Password"].ToString() + "," +      dr["City"].ToString();
                           strData += Environment.NewLine;
                        }
                    
                    // everytime when loop execute, it adds a line into the file
                        tw.Write(strData);
                    
                    // writing the contents in file
                        tw.Close();
                    
                    // closing the file
                        Response.Redirect("Downloads/" + filename);
                    
                    // exporting the file to the user as a popup to save as....
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2012-07-12
                      • 2011-02-19
                      • 2019-08-01
                      • 2019-04-09
                      • 1970-01-01
                      • 1970-01-01
                      • 2019-12-19
                      • 2021-06-02
                      相关资源
                      最近更新 更多