Подтвердить что ты не робот

Напишите в CSV файл и экспортируйте его?

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

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


Update:

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

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

https://github.com/jitbit/CsvExport

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

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

Ответ 3

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

Интуитивно, отправка CSV файла в браузер не должна приводить к исключению.

Подробнее см. здесь Является ли Response.End() считающимся вредным?

Ответ 4

Вот результат действия CSV, который я написал, который берет DataTable и преобразует его в CSV. Вы можете вернуть это из своего представления, и оно предложит пользователю загрузить файл. Вы должны легко преобразовать это в форму, совместимую с 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;
        }
    }
}

Ответ 5

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

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

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

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

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

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

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

  • Используйте случай 2, это приведет к генерации каждый раз, но очистке после доступа.