我正在编写一个通用处理程序,用于从安全的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上的内容是密码保护的,原因是它上面有一些敏感数据。
那么,对于如此大的文件,内存流是否可以安全使用?如果没有:有没有其他方法可以做到这一点,我忽略了?
提前致谢: - )
答案 0 :(得分:1)
MemoryStream
对于大文件来说是“安全的”。但是,您将整个文件加载到内存中,它将保留在那里,直到垃圾收集确定它是回收该内存的好时机。
8GB的RAM足以满足“中型”负载生产服务器的需求。当然,这是客观的,但如果单个中低流量的WebApp使用超过8GB的RAM,则应修改一些设计决策。
有两种方法可以避免将整个远程文件加载到内存中:
选项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();
}