Home » c# » Create text file and download

Create text file and download

Posted by: admin February 22, 2018 Leave a comment

Questions:

I’m trying to write to a text file in memory and then download that file without saving the file to the hard disk. I’m using the StringWriter to write the contents:

StringWriter oStringWriter = new StringWriter();
oStringWriter.Write("This is the content");

How do I then download this file?

EDIT:
It was combination of answers which gave me my solution. Here it is:

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

Instead of storing the data in memory and then sending it to the response stream, you can write it directly to the response stream:

using (StreamWriter writer = new StreamWriter(Response.OutputStream, Encoding.UTF8)) {
  writer.Write("This is the content");
}

The example uses the UTF-8 encoding, you should change that if you are using some other encoding.

Questions:
Answers:

This solved for me:

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

Questions:
Answers:

Basically you create an HttpHandler by implementing the IHttpHandler interface. In the ProcessRequest method you basically just write your text to context.Response. You also need to add a Content-Disposition http header:

context.Response.AddHeader("Content-Disposition", "attachment; filename=YourFileName.txt");

Also remember to set the ContentType:

context.Response.ContentType = "text/plain";

Questions:
Answers:

Just a small addition to the other answers. At the very end of a download I execute:

context.Response.Flush();
context.ApplicationInstance.CompleteRequest();

I learned that otherwise, the download sometimes does not complete successfully.

This Google Groups posting also notes that Response.End throws a ThreadAbortException which you could avoid by using the CompleteRequest method.

Questions:
Answers:

This is very simple, and the answer can be seen in this Microsoft KB Article: How to write binary files to the browser using ASP.NET and C#

Questions:
Answers:

I had many issues with this. Finnaly found a solution that seems to work everytime.

In most cases the user is going to click a button for the download. At this point it is best to redirect the page back to the same spot. add a parameter in the url that you can grab and read.

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");
    }

Questions:
Answers:

Extension of @Vinicious answer.

I had data that could contain commas. The common solution is to escape that piece of data by enclosing it in quotes, while making sure to also escape quotes that could also be a part of the data.

One rub I came against and a warning when writing CSV, excel will not like you if you put spaces trailing your commas. discovered solution to my problem from superuser answer

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;
    }
}

Below will cause a problem for excel. In excel the first quote will become part of the data and consequently than separate at the embedded comma. Spaces bad.

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