在 C# 中以小块下载大文件
Posted
技术标签:
【中文标题】在 C# 中以小块下载大文件【英文标题】:Download large file in small chunks in C# 【发布时间】:2012-11-26 13:54:37 【问题描述】:我需要下载一些超过 25 MB 的文件,但我的网络只允许请求 25 MB 的文件。
我正在使用以下代码
const long DefaultSize = 26214400;
long Chunk = 26214400;
long offset = 0;
byte[] bytesInStream;
public void Download(string url, string filename)
long size = Size(url);
int blocksize = Convert.ToInt32(size / DefaultSize);
int remainder = Convert.ToInt32(size % DefaultSize);
if (remainder > 0) blocksize++;
FileStream fileStream = File.Create(@"D:\Download TEST\" + filename);
for (int i = 0; i < blocksize; i++)
if (i == blocksize - 1)
Chunk = remainder;
HttpWebRequest req = (HttpWebRequest)System.Net.WebRequest.Create(url);
req.Method = "GET";
req.AddRange(Convert.ToInt32(offset), Convert.ToInt32(Chunk+offset));
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
// StreamReader sr = new StreamReader(resp.GetResponseStream());
using (Stream responseStream = resp.GetResponseStream())
bytesInStream = new byte[Chunk];
responseStream.Read(bytesInStream, 0, (int)bytesInStream.Length);
// Use FileStream object to write to the specified file
fileStream.Seek((int)offset, SeekOrigin.Begin);
fileStream.Write(bytesInStream,0, bytesInStream.Length);
offset += Chunk;
fileStream.Close();
public long Size(string url)
System.Net.WebRequest req = System.Net.HttpWebRequest.Create(url);
req.Method = "HEAD";
System.Net.WebResponse resp = req.GetResponse();
resp.Close();
return resp.ContentLength;
它可以在磁盘上正确写入内容,但内容不工作
【问题讨论】:
我无法真正提供答案,但您能单步执行代码吗?我建议缩小所有数字(例如,将最大块大小设置为 10 字节,将下载文件大小设置为 25 字节),然后逐步进行。如果涉及较小的块,可能会更容易发现您出错的地方。 你有没有得到任何最终解决方案,并且 working ?有答案:it still not working
你说
【参考方案1】:
您应该在写入之前检查读取了多少,类似这样(并且您不需要记住要查找的偏移量,写入时查找是自动的):
int read;
do
read = responseStream.Read(bytesInStream, 0, (int)bytesInStream.Length);
if (read > 0)
fileStream.Write(bytesInStream, 0, read);
while(read > 0);
【讨论】:
【参考方案2】:有一个类似的 SO 问题可能对您有所帮助 Segmented C# file downloader
和
How to open multiple connections to download single file?
还有这篇代码项目文章 http://www.codeproject.com/Tips/307548/Resume-Suppoert-Downloading
【讨论】:
【参考方案3】:范围从零开始,您应该从上限中减去 1。
request.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(offset, chunkSize + offset - 1);
我在以下链接中发布了正确的代码片段: https://***.com/a/48019611/1099716
【讨论】:
【参考方案4】:Akka 流可以帮助使用多线程从 System.IO.Stream 下载小块文件。 https://getakka.net/articles/intro/what-is-akka.html
Download 方法会将字节追加到以 long fileStart 开头的文件中。如果文件不存在,fileStart 值必须为 0。
using Akka.Actor;
using Akka.IO;
using Akka.Streams;
using Akka.Streams.Dsl;
using Akka.Streams.IO;
private static Sink<ByteString, Task<IOResult>> FileSink(string filename)
return Flow.Create<ByteString>()
.ToMaterialized(FileIO.ToFile(new FileInfo(filename), FileMode.Append), Keep.Right);
private async Task Download(string path, Uri uri, long fileStart)
using (var system = ActorSystem.Create("system"))
using (var materializer = system.Materializer())
HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
request.AddRange(fileStart);
using (WebResponse response = request.GetResponse())
Stream stream = response.GetResponseStream();
await StreamConverters.FromInputStream(() => stream, chunkSize: 1024)
.RunWith(FileSink(path), materializer);
【讨论】:
以上是关于在 C# 中以小块下载大文件的主要内容,如果未能解决你的问题,请参考以下文章
如何以小块上传带有ajax的文件并检查失败,重新上传失败的部分。
在 linux (centos 7) 中将一个大文件(例如 300GB)分割成 100MB 的小块
如何在 C# 中使用 Ionic-zip 下载大文件时修复 zip 文件损坏错误