使用内存流下载大文件

时间:2014-06-15 21:53:36

标签: c# ftp

我正在编写一个通用处理程序,用于从安全的FTP服务器下载相当大(400+ mb)的文件。我通过将响应流复制到MemoryStream然后二进制写入字节数组来使我的代码处理小的测试图像。

我的代码如下(DownloadFile.ashx):

// Set correct path
string path = ftpHelper.GetCompletePath();
path += "/" + loginId + "/" + folderName + "/" + fileName;

FtpWebRequest request = (FtpWebRequest)WebRequest.Create(path);
request.UsePassive = false;
request.Credentials = new NetworkCredential(ftpHelper.Username, ftpHelper.Password);

byte[] fileBytes = null;

using (var response = (FtpWebResponse)request.GetResponse())
{
    using (Stream responseStream = response.GetResponseStream())
    {
        using (var memoryStream = new MemoryStream())
        {
            if (responseStream != null) responseStream.CopyTo(memoryStream);
            fileBytes = memoryStream.ToArray();
        }
    }
 }

if (fileBytes.Length > 0)
{
     context.Response.AppendHeader("Content-Length", fileBytes.Length.ToString());
     context.Response.BinaryWrite(fileBytes);
}

request.Abort();

context.ApplicationInstance.CompleteRequest();

问题是:在一个8gb ram的实时网络服务器上(它目前使用的是现有ram的约60%,因为它是一个相当大的网站!它可能需要ram升级;-))可以安全地制作CopyTo ()并使用具有如此大文件的MemoryStream?

我知道我可以通过ftp://username:password@path.com将客户端上的下载链接直接设置到FTP服务器,但FTP上的内容是密码保护的,原因是它上面有一些敏感数据。

那么,对于如此大的文件,内存流是否可以安全使用?如果没有:有没有其他方法可以做到这一点,我忽略了?

提前致谢: - )

3 个答案:

答案 0 :(得分:1)

MemoryStream对于大文件来说是“安全的”。但是,您将整个文件加载到内存中,它将保留在那里,直到垃圾收集确定它是回收该内存的好时机。

8GB的RAM足以满足“中型”负载生产服务器的需求。当然,这是客观的,但如果单个中低流量的WebApp使用超过8GB的RAM,则应修改一些设计决策。

有两种方法可以避免将整个远程文件加载到内存中:

  1. 将其写入磁盘上的本地文件,并将该文件提供回WebApp客户端
  2. 直接对响应流进行分块写入
  3. 选项2可能类似于:

    //...
    using (Stream responseStream = response.GetResponseStream())
    {
        Response.BufferOutput= false;   // to prevent buffering 
        byte[] buffer = new byte[1024]; 
        int bytesRead = 0; 
        while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)  
        { 
             Response.OutputStream.Write(buffer, 0, bytesRead); 
        }
    }
    //...
    

答案 1 :(得分:0)

使用内存流应该没问题。请记住,您不需要立即编写整个文件,继续写入数据,直到您返回所有文件,然后关闭响应。

看看这个问题,了解如何以块的形式返回天数Download large file in small chunks in C#

答案 2 :(得分:0)

    void WriteFile(string path, string filename)
    {
        using (FileStream fs = File.OpenRead(path))
        {
            //response is HttpListenerContext.Response... 
            Response.ContentType = System.Net.Mime.MediaTypeNames.Application.Octet;
            Response.AddHeader("Content-disposition", "attachment; filename=" + filename); 
            byte[] buffer = new byte[64 * 1024];
            int read; 
            while ((read = fs.Read(buffer, 0, buffer.Length)) > 0)
            {
                Response.OutputStream.Write(buffer, 0, read);
                Response.OutputStream.Flush(); //seems to have no effect
            } 
            Response.OutputStream.Close();
        }
        File.Delete(path);
        Response.End();
    }