Написать в файл CSV и экспортировать его? - PullRequest
25 голосов
/ 23 сентября 2010

В C # ASP.net может кто-нибудь показать мне, как я могу записать записи из массива / списка в файл CSV на сервере, а затем открыть файл? Я думаю, что вторая часть будет что-то вроде - Response.Redirect ("http://myserver.com/file.csv"), однако не уверен, как записать файл на сервер.

Кроме того, если к этой странице обращаются многие пользователи, лучше ли каждый раз генерировать новый файл CSV или перезаписывать один и тот же файл? Будут ли проблемы с чтением / записью / блокировкой, если оба пользователя попытаются получить доступ к одному и тому же файлу CSV и т. Д .?


Обновление:

Это, вероятно, глупый вопрос, и я искал в Google, но я не могу найти окончательный ответ - как вы пишете файл CSV на веб-сервер и экспортируете его в C # ASP.net? Я знаю, как его сгенерировать, но я хотел бы сохранить его на www.mysite.com/my.csv и затем экспортировать.

Ответы [ 6 ]

54 голосов
/ 23 сентября 2010

Ром, ты делаешь это неправильно. Вы не хотите записывать файлы на диск, чтобы IIS мог их обслуживать. Это добавляет последствия для безопасности, а также увеличивает сложность. Все, что вам действительно нужно сделать, это сохранить CSV непосредственно в поток ответов.

Вот сценарий: пользователь хочет скачать CSV. Пользователь отправляет форму с подробной информацией о CSV, который они хотят. Вы готовите CSV, затем предоставляете пользователю URL-адрес страницы ASPX, который можно использовать для создания файла CSV и записи его в поток ответов. Пользователь нажимает на ссылку. Страница aspx пуста; На странице кода вы просто записываете CSV в поток ответов и завершаете его.

Вы можете добавить следующее к (я считаю, это правильно) Загрузка событие:

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());

запись в код потока ответов отсюда .

24 голосов
/ 02 марта 2015

Вот очень простой бесплатный класс CsvExport с открытым исходным кодом для C #. Ниже приведен пример ASP.NET MVC.

https://github.com/jitbit/CsvExport

Он заботится о переносе строк, запятых, экранировании кавычек, совместимости с MS Excel ... Просто добавьте один короткий .cs файл в свой проект, и все готово.

(отказ от ответственности: я один из авторов)

6 голосов
/ 20 февраля 2013

В комментарии об ответе Уилла вы можете заменить HttpContext.Current.Response.End(); на HttpContext.Current.ApplicationInstance.CompleteRequest();. Причина в том, что Response.End() выдает System.Threading.ThreadAbortException.Это прерывает поток.Если у вас есть регистратор исключений, он будет усеян ThreadAbortExceptions, что в данном случае является ожидаемым поведением.

Интуитивно, отправка файла CSV в браузер не должна вызывать исключение.здесь для более Response.End () считается вредным?

5 голосов
/ 28 октября 2010

Вот результат действия CSV, который я написал, который берет DataTable и преобразует его в CSV. Вы можете вернуть это из своего поля зрения, и оно предложит пользователю загрузить файл. Вы сможете легко преобразовать это в форму, совместимую со списком, или просто поместить свой список в таблицу данных.

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;
        }
    }
}
1 голос
/ 23 сентября 2010

Как записать в файл (простой поиск в Google) ... 1-й результат поиска

Что касается создания файла каждый раз, когда пользователь заходит на страницу ... каждый доступ будет действовать от своего имени. Ваше экономическое обоснование будет диктовать поведение.

Случай 1 - тот же файл, но не изменяется (этот тип случая может быть определен несколькими способами)

  • У вас была бы логика, которая создавала файл при необходимости, и доступ к нему осуществлялся только в том случае, если генерация не нужна.

Случай 2 - каждый пользователь должен создать свой собственный файл

  • Вы должны решить, как идентифицировать каждого пользователя, создать файл для каждого пользователя и получить доступ к файлу, который он должен видеть ... это может легко слиться с делом 1. Затем вы удаляете файл после подачи контента или нет, если это требует настойчивости.

Случай 3 - тот же файл, но генерация требуется для каждого доступа

  • Сценарий использования 2, это будет вызывать генерацию каждый раз, но очищаться после обращения.
0 голосов
/ 23 сентября 2010

проверить библиотеку csvreader / writer на http://www.codeproject.com/KB/cs/CsvReaderAndWriter.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...