Напишите в CSV файл и экспортируйте его?
В С# ASP.net, может ли кто-нибудь показать мне, как я могу писать записи из массива/списка в CSV файл на сервере, а затем открыть файл? Я думаю, что вторая часть будет похожа на: Response.Redirect( " http://myserver.com/file.csv" ), однако не уверен, как записать файл на сервера.
Также, если к этой странице обращаются многие пользователи, лучше ли каждый раз генерировать новый файл CSV или перезаписывать один и тот же файл? Были ли проблемы с чтением/записью/блокировкой, если оба пользователя попытаются получить доступ к одному и тому же файлу CSV и т.д.?
Update:
Это, наверное, глупый вопрос, и я искал в Google, но я не могу найти окончательный ответ - как вы пишете файл CSV на веб-сервере и экспортируете его на С# ASP.net? Я знаю, как его создать, но я хотел бы сохранить его на www.mysite.com/my.csv, а затем экспортировать.
Ответы
Ответ 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, это приведет к генерации каждый раз, но очистке после доступа.
Ответ 6
проверить библиотеку csvreader/writer на http://www.codeproject.com/KB/cs/CsvReaderAndWriter.aspx