【问题标题】:Create a .csv file in C#在 C# 中创建一个 .csv 文件
【发布时间】:2010-08-20 15:06:08
【问题描述】:

好的,我想用 C# 创建一个 .csv 文件。我环顾四周,发现很多人都在使用 system.IO.memorystream 和 system.io.streamwriter。

问题是这样的:我有一个 Web 应用程序。我想让用户能够导出到 excel。问题是,Excel 无法安装在服务器上(不要问)。我希望能够为报告编写 .csv 表导出。现在,所有报告的报告标题和数据都将不同(循环将解决此问题)。有人有示例或更好的资源供我参考吗?

【问题讨论】:

  • 看完之后。我真正需要做的就是循环并输出以逗号分隔的数据,并在行尾用 /n 分隔并继续循环直到完成...将文件保存为 .csv 然后关闭流...对吗?
  • 您还需要设置内容类型,如果数据可能包含", 或换行符,您也需要对其进行转义。我的答案中的代码。

标签: c# csv export


【解决方案1】:

这是我通常采用的方法。不过可能不是最有效的。

        /// <summary>
    /// Generates the contents of the log file.
    /// </summary>
    /// <returns>The contents of the log file.</returns>
    internal string GenerateLogFile()
    {
        StringBuilder csvExport = new StringBuilder();
        csvExport.AppendLine(Resources.CSVHeader);

        foreach (DataRow row in this.logEntries.Rows)
        {
            csvExport.AppendLine(
                string.Format(
                "\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\",\"{6}\",\"{7}\",\"{8}\", \"{9}\"",
                row[ColumnNames.LogTime], row[ColumnNames.Field1], row[ColumnNames.Field2], row[ColumnNames.Field3], row[ColumnNames.Field4], row[ColumnNames.Field5], row[ColumnNames.Field6], row[ColumnNames.Field7], row[ColumnNames.Field8], row[ColumnNames.Field9]));
        }

        return csvExport.ToString();
    }

    /// <summary>
    /// Adds the CSV file to the response.
    /// </summary>
    /// <param name="csvExportContents">The contents of the CSV file.</param>
    internal void DisplayLogFile(string csvExportContents)
    {
        byte[] data = new ASCIIEncoding().GetBytes(csvExportContents);

        HttpContext.Current.Response.Clear();
        HttpContext.Current.Response.ContentType = "APPLICATION/OCTET-STREAM";
        HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment; filename=Export.csv");
        HttpContext.Current.Response.OutputStream.Write(data, 0, data.Length);
        HttpContext.Current.Response.End();
    }

【讨论】:

  • CSVHeader 来自哪里?
  • 我看不到可能包含 " 的值将如何被转义。
  • @RealityDysfunction 我假设它来自 resx 文件。为了这个例子,只有一个字符串文字会更有用。
【解决方案2】:
private void WriteItem<T>(StreamWriter sr, T item)
{
    string itemString = item.ToString();
    if(itemString.IndexOfAny(new char[] { '"', ',', '\n', '\r' }) != -1)//skip test and always escape for different speed/filesize optimisation
    {
        sr.Write('"');
        sr.Write(itemString.Replace("\"", "\"\""));
        sr.Write('"');
    }
    else
        sr.Write(itemString);
}
private void WriteLine<T>(StreamWriter sr, IEnumerable<T> line)
{
    bool first = true;
    foreach(T item in line)
    {
        if(!first)
            sr.Write(',');
        first = false;
        WriteItem(sr, item);
    }
}
private void WriteCSV<T>(StreamWriter sr, IEnumerable<IEnumerable<T>> allLines)
{
    bool first = true;
    foreach(IEnumerable<T> line in allLines)
    {
        if(!first)
            sr.Write('\n');
        first = false;
        WriteLine(sr, line);
    }
}
private void WriteCSV<T>(HttpResponse response, IEnumerable<IEnumerable<T>> allLines)
{
    response.ContentType = "text/csv";
    WriteCSV(response.Output, allLines);
}

还值得发送带有推荐文件名的内容处置标头。

编辑:最近,在需要在枚举中的项目之间插入操作的情况下(例如上面的逗号和换行符),我更喜欢保留一个不断检查的布尔值,而是直接处理枚举数,然后将第一个元素与其余元素分开处理。我开始这样做是为了提高效率,但已经成长为发现它是对第一项不同的代码路径的更好表达。因此,我现在将上面的内容写为:

private void WriteLine<T>(StreamWriter sr, IEnumerable<T> line)
{
  using(var en = line.GetEnumerator())
  if(en.MoveNext())
  {
    WriteItem(sr, en.Current);
    while(en.MoveNext())
    {
      sr.Write(',');
      WriteItem(sr, en.Current);
    }
}
private void WriteCSV<T>(StreamWriter sr, IEnumerable<IEnumerable<T>> allLines)
{
    using(var en = allLines.GetEnumerator())
    if(en.MoveNext())
    {
      WriteLine(sr, en.Current);
      while(en.MoveNext())
      {
        sr.Write('\n');
        WriteLine(sr, en.Current);
      }
    }
}

【讨论】:

  • 实际使用示例会很好。
【解决方案3】:

您应该可以使用 System.IO.MemoryStreamSystem.IO.StreamWriter 的示例。

您可以将其作为 ASP.NET 中的 ResponseStream 返回,而不是将 MemoryStream 写入文件(确保设置适当的标头值,以便浏览器知道它正在下载文件)。

【讨论】:

    【解决方案4】:

    只有在使用 Office Interop 时才需要 Excel。使用 StringWriter,您只需创建一个文件并添加一些响应信息。只有在打开文件时才需要 Excel。

    【讨论】:

      【解决方案5】:

      创建 CSV 文件并没有什么神奇之处。 CSV 文件的唯一问题是没有真正的标准,大多数进口商只会在进口过程中实施一种特定的行为。如果幸运的话,你会得到一些可以猜得比较好的东西。

      生成 CSV 文件只是打印行的问题。至于实际细节,请熟悉:

      http://en.wikipedia.org/wiki/Comma-separated_values

      话虽如此,如果你想要导出到 Excel,你可以使用微软的 OOXML SDK:

      http://msdn.microsoft.com/en-us/library/bb448854.aspx

      OOXML SDK 是一个 C# 库,您可以使用它在服务器上生成 Excel 文件。 Brian Jones 博客是有关如何使用此库的绝佳资源:

      http://blogs.msdn.com/b/brian_jones/

      【讨论】:

      • 我需要在服务器上使用 Excel 吗?
      • 您不需要服务器上的 Excel 来运行 OOXML SDK。事实上,你甚至可以在带有 Mono 的 Linux 系统上运行它。
      【解决方案6】:

      如果您不介意使用 3rd 方库并且在您的项目中可以使用 LGPL 许可证,那么 FileHelpers 是一个很好的工具。

      【讨论】:

      • 我喜欢 FileHelpers!这个简单快速的库使将平面文件转换为对象变得容易。它还可以以面向对象的方式将对象转换为平面文本文件。而且速度很快。它有一个向导来帮助指导你。干杯!
      【解决方案7】:

      这是用于创建 csv 文件的函数:

       private async Task<string> WriteCSV<ViewModel>(IEnumerable<ViewModel> viewModels, string path)
                  {
                      Type itemType = typeof(ViewModel);
                      var props = itemType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                          .OrderBy(p => p.Name);
      
                      var blobName = string.Empty;
      
                      using (var ms = new MemoryStream())
                      {
      
                          using (var writer = new System.IO.StreamWriter(ms))
                          {
                              writer.WriteLine(string.Join(", ", props.Select(p => p.Name)));
      
                              foreach (var item in viewModels)
                              {
      
                                  writer.WriteLine(string.Join(", ", props.Select(p => p.GetValue(item, null))));
                              }
          }
      
       }
          }
      

      否则你可以参考以下链接:

      https://travelcodingnlotsmore.wordpress.com/2013/06/06/creating-csv-file-from-data-in-list-object-in-c/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-31
        • 2014-06-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多