5

在我工作地点的 ASP.net 站点上,以下代码块负责处理文件下载(注意:此处未使用 Response.TransmitFile,因为下载的内容是从 zip 文件流式传输的):

private void DownloadFile( Stream stream)
{
        int bytesRead;
        int chunkSize = 1048576; //1MB

        byte[] readBuffer = new byte[chunkSize];
        while ((bytesRead = stream.Read(readBuffer, 0, readBuffer.Length)) != 0)
            {
                if(!Response.IsClientConnected)
                    break;
                byte[] chunk = new byte[bytesRead];
                Array.Copy(readBuffer,0,chunk,0,bytesRead);
                Response.BinaryWrite(chunk);
                Response.Flush();
        }
        stream.Close();
}

我们的用户经常下载数百 MB 的文件,这会很快消耗服务器内存。我的假设是这是由于响应缓冲造成的。那有意义吗?

我刚刚阅读了 Response 对象的“缓冲区”属性。如果我将其设置为 false,是否会阻止 Response.BinaryWrite() 调用缓冲内存中的数据?一般来说,在这种情况下限制内存使用的好方法是什么?也许我应该从 zip 流到一个临时文件,然后调用 Response.TransmitFile()?

编辑:除了可能的解决方案之外,我对上面代码中存在的内存使用问题的解释非常感兴趣。为什么这会消耗超过 1MB,即使每次循环迭代都调用 Response.Flush?它只是在每次循环迭代中发生的不必要的堆分配(并且不会立即得到 GC),还是有其他事情在起作用?

4

1 回答 1

5

这是我正在为此工作的一些代码。它使用 8000 字节的缓冲区以块的形式发送文件。对大文件的一些非正式测试显示分配的内存显着减少。

int BufferSize = 8000;
FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
try {
  long fileSize = stream.Length;

  long dataLeftToRead = fileSize;
  int chunkLength;
  buffer = new Byte[BufferSize];

  while (dataLeftToRead > 0) {
    if (!Response.IsClientConnected) {
      break;
    }
    chunkLength = stream.Read(buffer, 0, BufferSize);

    Response.OutputStream.Write(buffer, 0, chunkLength);
    Response.Flush();

    dataLeftToRead -= chunkLength;
  }
}
finally {
  if (stream != null) {
    stream.Close();
}

编辑以修复语法错误和缺失值

于 2010-01-22T21:25:48.767 回答