简体   繁体   English

写入CSV文件并导出?

[英]Write to CSV file and export it?

In C# ASP.net, could someone show me how I can write entries from an Array/List to a CSV file on the server and then open the file? 在C#ASP.net中,有人可以告诉我如何将数组/列表中的条目写入服务器上的CSV文件,然后打开文件吗? I think the second part would be something like - Response.Redirect(" http://myserver.com/file.csv "), however not sure on how to write the file on the server. 我认为第二部分将是 - Response.Redirect(“ http://myserver.com/file.csv ”),但不确定如何在服务器上写入文件。

Also if this page is accessed by many users, is it better to generate a new CSV file every time or overwrite the same file? 此外,如果许多用户访问此页面,是否每次生成新的CSV文件或覆盖同一文件更好? Would there be any read/write/lock issues if both users try accessing the same CSV file etc.? 如果两个用户都尝试访问相同的CSV文件等,是否会出现读/写/锁定问题?


Update: 更新:

This is probably a silly question and I have searched on Google but I'm not able to find a definitive answer - how do you write a CSV file to the webserver and export it in C# ASP.net? 这可能是一个愚蠢的问题,我在Google上搜索过,但我无法找到明确的答案 - 你如何将CSV文件写入网络服务器并将其导出到C#ASP.net? I know how to generate it but I would like to save it to www.mysite.com/my.csv and then export it. 我知道如何生成它,但我想将其保存到www.mysite.com/my.csv然后导出它。

Rom, you're doing it wrong. 罗姆,你做错了。 You don't want to write files to disk so that IIS can serve them up. 您不希望将文件写入磁盘,以便IIS可以为它们提供服务。 That adds security implications as well as increases complexity. 这增加了安全隐患并增加了复杂性。 All you really need to do is save the CSV directly to the response stream. 您真正需要做的就是将CSV直接保存到响应流中。

Here's the scenario: User wishes to download csv. 这是场景:用户希望下载csv。 User submits a form with details about the csv they want. 用户提交一个表单,其中包含有关他们想要的csv的详细信息。 You prepare the csv, then provide the user a URL to an aspx page which can be used to construct the csv file and write it to the response stream. 您准备csv,然后向用户提供一个aspx页面的URL,该页面可用于构造csv文件并将其写入响应流。 The user clicks the link. 用户单击该链接。 The aspx page is blank; aspx页面是空白的; in the page codebehind you simply write the csv to the response stream and end it. 在页面代码隐藏中,您只需将csv写入响应流并结束它。

You can add the following to the (I believe this is correct) Load event: 您可以添加以下内容(我相信这是正确的) 加载事件:

string attachment = "attachment; filename=MyCsvLol.csv";
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.AddHeader("content-disposition", attachment);
HttpContext.Current.Response.ContentType = "text/csv";
HttpContext.Current.Response.AddHeader("Pragma", "public");

var sb = new StringBuilder();
foreach(var line in DataToExportToCSV)
  sb.AppendLine(TransformDataLineIntoCsv(line));

HttpContext.Current.Response.Write(sb.ToString());

writing to the response stream code ganked from here . 写入响应流代码从这里开始

Here's a very simple free open-source CsvExport class for C#. 这是一个非常简单的C#免费开源CsvExport类。 There's an ASP.NET MVC example at the bottom. 底部有一个ASP.NET MVC示例。

https://github.com/jitbit/CsvExport https://github.com/jitbit/CsvExport

It takes care about line-breaks, commas, escaping quotes, MS Excel compatibilty... Just add one short .cs file to your project and you're good to go. 它关注换行符,逗号,转义引号,MS Excel兼容性...只需将一个简短的.cs文件添加到您的项目中,您就可以开始了。

(disclaimer: I'm one of the contributors) (免责声明:我是贡献者之一)

A comment about Will's answer, you might want to replace HttpContext.Current.Response.End(); 关于Will的答案的评论,你可能想要替换HttpContext.Current.Response.End(); with HttpContext.Current.ApplicationInstance.CompleteRequest(); 使用HttpContext.Current.ApplicationInstance.CompleteRequest(); The reason is that Response.End() throws a System.Threading.ThreadAbortException . 原因是Response.End()抛出System.Threading.ThreadAbortException It aborts a thread. 它中止一个线程。 If you have an exception logger, it will be littered with ThreadAbortExceptions, which in this case is expected behavior. 如果你有一个异常记录器,那么它将充满ThreadAbortExceptions,在这种情况下是预期的行为。

Intuitively, sending a CSV file to the browser should not raise an exception. 直观地说,将CSV文件发送到浏览器不应引发异常。

See here for more Is Response.End() considered harmful? 在这里查看更多是否Response.End()被认为是有害的?

Here is a CSV action result I wrote that takes a DataTable and converts it into CSV. 这是我写的一个CSV动作结果,它采用DataTable并将其转换为CSV。 You can return this from your view and it will prompt the user to download the file. 您可以从视图中返回此内容,它将提示用户下载该文件。 You should be able to convert this easily into a List compatible form or even just put your list into a DataTable. 您应该能够轻松地将其转换为List兼容表单,甚至只需将列表放入DataTable即可。

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Data;

namespace Detectent.Analyze.ActionResults
{
    public class CSVResult : ActionResult
    {
        /// <summary>
        /// Converts the columns and rows from a data table into an Microsoft Excel compatible CSV file.
        /// </summary>
        /// <param name="dataTable"></param>
        /// <param name="fileName">The full file name including the extension.</param>
        public CSVResult(DataTable dataTable, string fileName)
        {
            Table = dataTable;
            FileName = fileName;
        }

        public string FileName { get; protected set; }
        public DataTable Table { get; protected set; }




        public override void ExecuteResult(ControllerContext context)
        {
            StringBuilder csv = new StringBuilder(10 * Table.Rows.Count * Table.Columns.Count);

            for (int c = 0; c < Table.Columns.Count; c++)
            {
                if (c > 0)
                    csv.Append(",");
                DataColumn dc = Table.Columns[c];
                string columnTitleCleaned = CleanCSVString(dc.ColumnName);
                csv.Append(columnTitleCleaned);
            }
            csv.Append(Environment.NewLine);
            foreach (DataRow dr in Table.Rows)
            {
                StringBuilder csvRow = new StringBuilder();
                for(int c = 0; c < Table.Columns.Count; c++)
                {
                    if(c != 0)
                        csvRow.Append(",");

                    object columnValue = dr[c];
                    if (columnValue == null)
                        csvRow.Append("");
                    else
                    {
                        string columnStringValue = columnValue.ToString();


                        string cleanedColumnValue = CleanCSVString(columnStringValue);

                        if (columnValue.GetType() == typeof(string) && !columnStringValue.Contains(","))
                        {
                            cleanedColumnValue = "=" + cleanedColumnValue; // Prevents a number stored in a string from being shown as 8888E+24 in Excel. Example use is the AccountNum field in CI that looks like a number but is really a string.
                        }
                        csvRow.Append(cleanedColumnValue);
                    }
                }
                csv.AppendLine(csvRow.ToString());
            }

            HttpResponseBase response = context.HttpContext.Response;
            response.ContentType = "text/csv";
            response.AppendHeader("Content-Disposition", "attachment;filename=" + this.FileName);
            response.Write(csv.ToString());
        }

        protected string CleanCSVString(string input)
        {
            string output = "\"" + input.Replace("\"", "\"\"").Replace("\r\n", " ").Replace("\r", " ").Replace("\n", "") + "\"";
            return output;
        }
    }
}

How to write to a file (easy search in Google) ... 1st Search Result 如何写入文件(在Google中轻松搜索)... 第一个搜索结果

As far as creation of the file each time a user accesses the page ... each access will act on it's own behalf. 至于每次用户访问页面时创建文件......每次访问都将代表自己的行为。 You business case will dictate the behavior. 您的业​​务案例将决定行为。

Case 1 - same file but does not change (this type of case can have multiple ways of being defined) 案例1 - 相同的文件但不会改变(这种类型的案例可以有多种方式被定义)

  • You would have logic that created the file when needed and only access the file if generation is not needed. 您将拥有在需要时创建文件的逻辑,并且只有在不需要生成时才访问该文件。

Case 2 - each user needs to generate their own file 案例2 - 每个用户都需要生成自己的文件

  • You would decide how you identify each user, create a file for each user and access the file they are supposed to see ... this can easily merge with Case 1. Then you delete the file after serving the content or not if it requires persistence. 您将决定如何识别每个用户,为每个用户创建文件以及访问他们应该看到的文件...这可以轻松地与案例1合并。然后在提供内容后删除文件,如果需要持久性。

Case 3 - same file but generation required for each access 案例3 - 每个访问都需要生成相同的文件

  • Use Case 2, this will cause a generation each time but clean up once accessed. 使用案例2,这将导致每次生成一次,但一旦访问就清理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM