我有以下代码...
public partial class DownloadFile : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string FilePath = "[FTPPath]";
Download downloadFile = new Download();
Server.ScriptTimeout = 54000;
try
{
long size = downloadFile.GetFileSize(FilePath);
using (FtpWebResponse ftpResponse = downloadFile.BrowserDownload(FilePath))
using (Stream streamResponse = ftpResponse.GetResponseStream())
{
string fileName = FilePath.Substring(FilePath.LastIndexOf("/") + 1);
int bufferSize = 65536;
byte[] buffer = new byte[bufferSize];
int readCount;
readCount = streamResponse.Read(buffer, 0, bufferSize);
// Read file into buffer
//streamResponse.Read(buffer, 0, (int)size);
Response.Clear();
Response.Buffer = false;
Response.BufferOutput = false;
//Apparently this line helps with old version of IE that like to cache stuff no matter how much you tell them!
Response.AddHeader("Pragma", "public");
//Expires: 0 forces the browser to always thing the page is "stale" therefore forcing it to never cache the page and therefore always re-downloads the page when viewed. Therefore no nasty experiences if we change the authentication details.
Response.Expires = 0;
//Again this line forces the browser not to cache the page.
Response.AddHeader("Cache-Control", "no-cache, must-revalidate");
Response.AddHeader("Cache-Control", "public");
Response.AddHeader("Content-Description", "File Transfer");
Response.ContentType = "application/zip";
Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
Response.AddHeader("Content-Transfer-Encoding", "binary");
Response.AddHeader("Content-Length", size.ToString());
// writes buffer to OutputStream
while (readCount > 0)
{
Response.OutputStream.Write(buffer, 0, bufferSize);
readCount = streamResponse.Read(buffer, 0, bufferSize);
Response.Flush();
}
Response.End();
Server.ScriptTimeout = 90;
}
}
catch (Exception ex)
{
Response.Write("<p>" + ex.Message + "</p>");
Server.ScriptTimeout = 90;
}
}
}
从 FTP 下载 .zip 文件(请忽略有关防止缓存的 header 垃圾,除非这与问题相关)。
所以 downloadFile
是我使用启用 SSL 的 FTPWebRequest
/Response
编写的一个类,它可以做两件事;一种是返回 FTP 上文件的文件大小 (GetFileSize
),另一种是设置 FtpWebRequest.Method = WebRequestMethods.Ftp.DownloadFile
以允许下载文件。
现在代码似乎可以完美运行,您会下载一个与 FTP 上的大小完全相同的精美 zip,但是,这就是怪癖开始的地方。
无论多小,zip 文件总是会损坏。理论上,非常小的文件应该没问题,但稍后您就会明白原因。因此,我决定比较二进制文件。
如果我将
bufferSize
设置为文件大小以外的任何值 (即 1024、2048、65536),前 16k(16384 字节)下载 完美,然后流只是将零写入到末尾 文件。如果我设置
bufferSize = size
(文件大小),则流似乎会下载完整的文件,直到您仔细观察。该文件在前 64k 之前都是精确的副本,然后下载的文件中会出现一个额外的字符(该字符似乎永远不会相同)。在这个额外的字节之后,文件再次完全相同。每 64k 似乎就会添加一个额外的字节,这意味着到 65MB 文件结束时,这两个文件严重不同步。由于下载长度受到服务器上文件大小的限制,因此下载文件中的文件末尾会被截断。当所有 CRC 检查失败时,存档将允许对其进行访问。
任何帮助将不胜感激。干杯。
现在稍微更改了我的代码,以使用 WebRequest
和 WebResponse
从 Web 服务器本身使用 Http 获取 zip。这是代码...
public partial class DownloadFile : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string FilePath = [http path];
Server.ScriptTimeout = 54000;
try
{
WebRequest HWR = WebRequest.Create(FilePath);
HWR.Method = WebRequestMethods.File.DownloadFile;
using (WebResponse FWR = HWR.GetResponse())
using (BinaryReader streamResponse = new BinaryReader(FWR.GetResponseStream()))
{
string fileName = FilePath.Substring(FilePath.LastIndexOf("/") + 1);
int bufferSize = 2048;
byte[] buffer = new byte[bufferSize];
int readCount;
readCount = streamResponse.Read(buffer, 0, bufferSize);
Response.Clear();
Response.Buffer = false;
Response.BufferOutput = false;
//Apparently this line helps with old version of IE that like to cache stuff no matter how much you tell them!
Response.AddHeader("Pragma", "public");
//Expires: 0 forces the browser to always thing the page is "stale" therefore forcing it to never cache the page and therefore always re-downloads the page when viewed. Therefore no nasty experiences if we change the authentication details.
Response.Expires = 0;
//Again this line forces the browser not to cache the page.
Response.AddHeader("Cache-Control", "no-cache, must-revalidate");
Response.AddHeader("Cache-Control", "public");
Response.AddHeader("Content-Description", "File Transfer");
Response.ContentType = "application/zip";
Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
Response.AddHeader("Content-Transfer-Encoding", "binary");
// writes buffer to OutputStream
while (readCount > 0)
{
Response.OutputStream.Write(buffer, 0, bufferSize);
Response.Flush();
readCount = streamResponse.Read(buffer, 0, bufferSize);
}
//Response.Write(testString);
Response.End();
Server.ScriptTimeout = 90;
}
}
catch (Exception ex)
{
Response.Write("<p>" + ex.Message + "</p>");
Server.ScriptTimeout = 90;
}
}
}
这段代码更简单,但它仍然会破坏数据。我确信我做错了一些非常简单的事情,但我就是找不到它或找到一个测试来告诉我哪里出错了。请帮忙:)
最佳答案
在线
Response.OutputStream.Write(buffer, 0, bufferSize);
将 bufferSize 更改为 readCount,以便您只写入实际读取的数字。
关于ASP.NET - response.outputstream.write 要么写入 16k,然后全为 0,要么每 64k 写入除 insetrs 之外的所有字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8168660/