Я пытаюсь записать в текстовый файл в памяти, а затем загрузить этот файл без сохранения файла на жесткий диск. Я использую StringWriter
для записи содержимого:
StringWriter oStringWriter = new StringWriter();
oStringWriter.Write("This is the content");
Как загрузить этот файл?
EDIT: Это была комбинация ответов, которые дали мне мое решение. Вот он:
StringWriter oStringWriter = new StringWriter();
oStringWriter.WriteLine("Line 1");
Response.ContentType = "text/plain";
Response.AddHeader("content-disposition", "attachment;filename=" + string.Format("members-{0}.csv",string.Format("{0:ddMMyyyy}",DateTime.Today)));
Response.Clear();
using (StreamWriter writer = new StreamWriter(Response.OutputStream, Encoding.UTF8))
{
writer.Write(oStringWriter.ToString());
}
Response.End();
Вместо того, чтобы хранить данные в памяти и затем отправлять их в поток ответов, вы можете записать их непосредственно в поток ответов:
using (StreamWriter writer = new StreamWriter(Response.OutputStream, Encoding.UTF8)) {
writer.Write("This is the content");
}
В примере используется кодировка UTF-8, вы должны изменить это, если используете другую кодировку.
text/plain; charset=utf-8
.
Это решило для меня:
MemoryStream ms = new MemoryStream();
TextWriter tw = new StreamWriter(ms);
tw.WriteLine("Line 1");
tw.WriteLine("Line 2");
tw.WriteLine("Line 3");
tw.Flush();
byte[] bytes = ms.ToArray();
ms.Close();
Response.Clear();
Response.ContentType = "application/force-download";
Response.AddHeader("content-disposition", "attachment; filename=file.txt");
Response.BinaryWrite(bytes);
Response.End();
В основном вы создаете HttpHandler, реализуя интерфейс IHttpHandler
. В методе ProcessRequest
вы в основном просто пишете текст в context.Response
. Вам также нужно добавить заголовок Content-Disposition
http:
context.Response.AddHeader("Content-Disposition", "attachment; filename=YourFileName.txt");
Также не забудьте установить ContentType
:
context.Response.ContentType = "text/plain";
Просто небольшое дополнение к другим ответам. В самом конце загрузки я выполняю:
context.Response.Flush();
context.ApplicationInstance.CompleteRequest();
Я узнал, что в противном случае загрузка иногда не завершается успешно.
В этой публикации Google Groups также отмечается, что Response.End
выбрасывает ThreadAbortException
, которого можно избежать, используя метод CompleteRequest
.
Расширение @Vinicious ответа.
У меня были данные, содержащие запятые. Общее решение заключается в том, чтобы избежать этой части данных, заключая ее в кавычки, при этом также избегая кавычек, которые также могут быть частью данных.
Один руб, против которого я выступил, и предупреждение при написании CSV, excel не понравится вам, если вы поместите пробелы в запятую. обнаружено решение моей проблемы из ответа суперпользователя
protected void btnDownload_Click(object sender, EventArgs e)
{
MemoryStream ms = new MemoryStream();
TextWriter tw = new StreamWriter(ms, System.Text.Encoding.UTF8);
var structures = KAWSLib.BusinessLayer.Structure.GetStructuresInService();
// *** comma delimited
tw.Write("Latitude, Longitude, CountySerial, StructureType, Orientation, District, RoutePre, RouteNo, LocationDesc");
foreach (var s in structures)
{
tw.Write(Environment.NewLine + string.Format("{0:#.000000},{1:#.000000},{2},{3},{4},{5},{6},{7},{8}", s.LATITUDE, s.LONGITUDE, s.CO_SER, EscapeIfNeeded(s.SuperTypeLookup.SHORTDESC), EscapeIfNeeded(s.OrientationLookup.SHORTDESC), s.DISTRICT, s.ROUTE_PREFIX, s.RouteValue, EscapeIfNeeded(s.LOC_DESC)));
}
tw.Flush();
byte[] bytes = ms.ToArray();
ms.Close();
Response.Clear();
Response.ContentType = "application/force-download";
Response.AddHeader("content-disposition", "attachment; filename=" + string.Format("kaws-structures-{0:yyyy.MM.dd}.csv", DateTime.Today));
Response.BinaryWrite(bytes);
Response.End();
}
string EscapeIfNeeded(string s)
{
if (s.Contains(","))
{
return "\"" + s.Replace("\"", "\"\"") + "\"";
}
else
{
return s;
}
}
Ниже приведена проблема для excel. В excel первая цитата станет частью данных и, следовательно, будет разделена на встроенную запятую. Пробелы плохие.
tw.Write(Environment.NewLine + string.Format("{0:#.000000}, {1:#.000000}, {2}, {3}, {4}, {5}, {6}, {7}, {8}", s.LATITUDE, s.LONGITUDE, s.CO_SER, EscapeIfNeeded(s.SuperTypeLookup.SHORTDESC), EscapeIfNeeded(s.OrientationLookup.SHORTDESC), s.DISTRICT, s.ROUTE_PREFIX, s.RouteValue, EscapeIfNeeded(s.LOC_DESC)));
У меня было много проблем с этим. Finnaly нашел решение, которое, кажется, работает каждый раз.
В большинстве случаев пользователь нажимает кнопку для загрузки. На этом этапе лучше перенаправить страницу обратно в одно и то же место. добавьте параметр в URL-адрес, который вы можете захватить и прочитать.
example (www.somewhere.com/mypage.aspx?print=stuff)
<asp:Button ID="btn" runat="server" Text="print something" OnClick="btn_Click" />
protected void Page_Load(object sender, EventArgs e) {
if (Request["print"] == "stuff") { Print("my test content"); }
}
/* or pass byte[] content*/
private void Print(string content ){
Response.ContentType = "text/plain";
Response.AddHeader("content-disposition", "attachment;filename=myFile.txt");
// Response.BinaryWrite(content);
Response.Write(content);
Response.Flush();
Response.End();
}
protected void btn_Click(object sender, EventArgs e) {
// postbacks give you troubles if using async.
// Will give an error when Response.End() is called.
Response.Redirect(Request.Url + "?print=queue");
}
Это очень просто, и ответ можно увидеть в этой статье Microsoft KB: Как записать двоичные файлы в браузер с помощью ASP.NET и С#/a >