5

I have a site where a user can download a file. Some files are extremely large (the largest being 323 MB). When I test it to try and download this file I get an out-of-memory exception. The only way I know to download the file is below. The reason I'm using the code below is that the URL is encoded and I can't let the user link directly to the file. Is there another way to download this file without having to read the whole thing into a byte array?

  FileStream fs = new FileStream(context.Server.MapPath(url),
                                 FileMode.Open,
                                 FileAccess.Read);

  BinaryReader br = new BinaryReader(fs);
  long numBytes = new FileInfo(context.Server.MapPath(url)).Length;
  byte[] bytes = br.ReadBytes((int) numBytes);

  string filename = Path.GetFileName(url);
  context.Response.Buffer = true;
  context.Response.Charset = "";

  context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
  context.Response.ContentType = "application/x-rar-compressed";
  context.Response.AddHeader("content-disposition", "attachment;filename=" + filename);

  context.Response.BinaryWrite(bytes);
  context.Response.Flush();
  context.Response.End();
Rahul
  • 3,293
  • 2
  • 31
  • 43
  • 1
    I'll ask the obvious question: can you read a fixed chunk from the BinaryReader in a loop, writing it out to the Response.BinaryWrite? I don't see any reason why you need to read in the entire file to memory as a single operation. – Joe Oct 03 '09 at 00:03

2 Answers2

17

Instead of

context.Response.BinaryWrite(bytes);

use

context.Response.TransmitFile(context.Server.MapPath(url));

This will avoid reading the entire file into memory.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
3

Try something like this:

using (var br = new BinaryReader(fs))
{
    FileStream toFile = File.OpenWrite(ToFileName);
    byte[] buff = new byte[2000];
    while (reader.Read(buff, 0, 2000) > 0)
    {
        toFile.Write(buff, 0, 2000);
        toFile.Flush();
    }
}

The important thing is that you use a smaller buffer and flush the write stream to clear out the memory.

Right now you are holding the entire file that you are downloading in both your BinaryReader and BinaryWriter. Chunking the download into a smaller buffer alleviates this burden on memory.

Rahul
  • 3,293
  • 2
  • 31
  • 43
overstood
  • 985
  • 6
  • 7