2012-07-27 71 views
2

这是我的C#代码从我的服务器下载ZIP文件。当我下载我没有收到该文件,但它被部分下载。文件没有完全下载

public static void Download(String strURLFileandPath, String strFileSaveFileandPath) 
{ 
    HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(strURLFileandPath); 
    HttpWebResponse ws = (HttpWebResponse)wr.GetResponse(); 
    Stream str = ws.GetResponseStream(); 
    byte[] inBuf = new byte[100000]; 
    int bytesToRead = (int)inBuf.Length; 
    int bytesRead = 0; 
    while (bytesToRead > 0) 
    { 
     int n = str.Read(inBuf, bytesRead, bytesToRead); 
     if (n == 0) 
      break; 
     bytesRead += n; 
     bytesToRead -= n; 
    } 
    try 
    { 

     FileStream fstr = new FileStream(strFileSaveFileandPath, FileMode.OpenOrCreate, FileAccess.Write); 
     fstr.Write(inBuf, 0, bytesRead); 
     str.Close(); 
     fstr.Close(); 
    } 
    catch (Exception e) { 
     MessageBox.Show(e.Message); 
    } 
} 

我的事情的问题在这里

byte[] inBuf = new byte[100000]; 

发生当我增加byte[] inBuf = new byte[100000];价值byte[] inBuf = new byte[10000000];

该文件是完全下载。

但我的问题是,如果我下载大于50 MB的文件(例如:200 MB)。

这种方法不好。

谁能告诉我如何解决这个问题?

+1

你的键盘似乎有同样的问题。 :) – leppie 2012-07-27 12:06:47

+0

不要你在他的文件大小,你的下载 – JohnnBlade 2012-07-27 12:09:54

回答

3

您可以使用Stream.CopyTo()方法直接从流复制到流。

甚至更​​简单:使用WebClient类及其DownloadFile方法下载文件。该解决方案将取代您的完整方法:

var client = new WebClient(); 
client.DownloadFile(strURLFileandPath, strFileSaveFileandPath); 
+0

谢谢重播 头文件得到响应但为什么表单会不响应? – Arun 2012-07-27 14:34:56

+0

这是因为下载是在与UI相同的线程中执行的。当文件被下载时,UI不能处理任何消息。您应该使用[DownloadFileAsync](http://msdn.microsoft.com/en-us/library/ms144196)方法并将事件处理程序附加到'DownloadFileCompleted'事件,以便知道下载何时完成。请注意,您的下载方法调用将立即返回。任何需要完整本地文件的代码都必须放在事件处理程序中! – fero 2012-07-27 14:50:05

+0

谢谢你。 我管理与后台工作的问题 我希望为此设置一个进度条。是webclient有任何事件的下载进度? 如果不是我如何设置进度条? – Arun 2012-07-27 14:56:48

0

在读取文件时写入文件。这样,在写入或完成下载之前,您不必将所有字节保留在内存中。

FileStream fstr = new FileStream(strFileSaveFileandPath, FileMode.OpenOrCreate, FileAccess.Write); 
int bytesRead; 
do 
{ 
    bytesRead = str.Read(inBuf, 0, bytesToRead); 
    fstr.Write(inBuf, 0, bytesRead); 
}while (bytesToRead > 0); 

str.Close(); 
fstr.Close(); 
0

由于FERO建议最好使用Stream.CopyTo()

但是,如果你决心做副本流,以手动方式流(或需要知道如何使用流在将来),您绝不应手动指定缓冲区大小。您通常需要使用缓冲区的最大大小没有重叠,以避免过多的内存消耗,在ResponseSream的情况下,你可以得到ContentLength您的StreamReader

HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(strURLFileandPath); 
HttpWebResponse ws = (HttpWebResponse)wr.GetResponse(); 
Stream str = ws.GetResponseStream(); 
byte[] inBuf = new byte[str.ContentLength]; 
int bytesToRead = (int)inBuf.Length; 

还记得和你Flush()输出。

+0

,如果文件真的很大,那么效果不好 – Qnan 2012-07-27 12:11:39

+0

@MikhailKozhevnikov我已经编辑过反思和澄清,这不是最好的soltuion,但只是他的问题的答案。最好的解决方案是避免手动迭代流的copyto方法。 – 2012-07-27 12:15:01