C# 如何将文件拆分为多个部分并下载

C# 如何将文件拆分为多个部分并下载,c#,http,web,download,C#,Http,Web,Download,我正在为c#开发一个拆分下载程序。它可以很好地下载(因此逻辑是有效的),但问题是它下载的任何文件都会被破坏。我不知道如何修理它。代码如下: private void mergeClean() { const int chunkSize = 1 * 1024; // 2KB using (var output = File.Create("output.jpg")) { foreach (var file in Fil

我正在为c#开发一个拆分下载程序。它可以很好地下载(因此逻辑是有效的),但问题是它下载的任何文件都会被破坏。我不知道如何修理它。代码如下:

private void mergeClean()
    {
        const int chunkSize = 1 * 1024; // 2KB
        using (var output = File.Create("output.jpg"))
        {
            foreach (var file in Files)
            {
                using (var input = File.OpenRead(file))
                {
                    var buffer = new byte[chunkSize];
                    int bytesRead;
                    while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        output.Write(buffer, 0, bytesRead);
                    }
                }
            }
        }

        foreach (var file in Files)
        {
            File.Delete(file);
        }
    }

    private void SaveFileStream(String path, Stream stream)
    {
        var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
        stream.CopyTo(fileStream);
        fileStream.Dispose();
    }

    public void SplitDownload(string URL)
    {
        System.Net.WebRequest req = System.Net.HttpWebRequest.Create(URL);
        req.Method = "HEAD";
        System.Net.WebResponse resp = req.GetResponse();
        var responseLength = double.Parse(resp.Headers.Get("Content-Length"));
        var partSize = Math.Ceiling(responseLength / 10);
        var previous = 0;

        for (int i = (int)partSize; i <= responseLength; i = i + (int)partSize)
        {
            Thread t = new Thread(() => Download(URL, previous, i));
            t.Start();
            t.Join();
            previous = i;
        }

        mergeClean();
    }

    private void Download(string URL, int Start, int End)
    {
        Console.WriteLine(String.Format("{0},{1}", Start, End));

        HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(URL);
        myHttpWebRequest.AddRange(Start, End);
        HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
        Stream streamResponse = myHttpWebResponse.GetResponseStream();
        String name = GenerateTempName();
        SaveFileStream(name, streamResponse);
        Files.Add(name);
    }
private void mergeClean()
{
常量int chunkSize=1*1024;//2KB
使用(var output=File.Create(“output.jpg”))
{
foreach(文件中的var文件)
{
使用(var input=File.OpenRead(File))
{
var buffer=新字节[chunkSize];
int字节读取;
而((bytesRead=input.Read(buffer,0,buffer.Length))>0)
{
输出写入(缓冲区,0,字节读取);
}
}
}
}
foreach(文件中的var文件)
{
文件。删除(文件);
}
}
私有void SaveFileStream(字符串路径、流)
{
var fileStream=newfilestream(路径,FileMode.Create,FileAccess.Write);
CopyTo(fileStream);
Dispose();
}
公共void SplitDownload(字符串URL)
{
System.Net.WebRequest req=System.Net.HttpWebRequest.Create(URL);
请求方法=“头”;
System.Net.WebResponse resp=req.GetResponse();
var responseLength=double.Parse(resp.Headers.Get(“内容长度”));
var零件尺寸=数学上限(响应长度/10);
var-previous=0;
对于(inti=(int)partSize;我下载(URL,previous,i));
t、 Start();
t、 Join();
先前=i;
}
mergeClean();
}
私有void下载(字符串URL、int Start、int End)
{
WriteLine(String.Format(“{0},{1}”,Start,End));
HttpWebRequest myHttpWebRequest=(HttpWebRequest)WebRequest.Create(URL);
myHttpWebRequest.AddRange(开始、结束);
HttpWebResponse myHttpWebResponse=(HttpWebResponse)myHttpWebRequest.GetResponse();
streamResponse=myHttpWebResponse.GetResponseStream();
字符串名称=GenerateTempName();
SaveFileStream(名称、streamResponse);
文件。添加(名称);
}
下面是一个示例,说明它的作用:

更新代码:

static string GenerateTempName(int start)
    {
        String name = String.Format("{0:D6}.tmp", start);
        return name;
    }

    static public List<string> Files = new List<string>();

    static private void mergeClean()
    {
        Files.Sort();
        const int chunkSize = 1 * 1024; // 2KB
        using (var output = File.Create("output.jpg"))
        {
            foreach (var file in Files)
            {
                using (var input = File.OpenRead(file))
                {
                    var buffer = new byte[chunkSize];
                    int bytesRead;
                    while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        output.Write(buffer, 0, bytesRead);
                    }
                }
            }
        }

        foreach (var file in Files)
        {
            File.Delete(file);
        }
    }
静态字符串GenerateTempName(int start)
{
String name=String.Format(“{0:D6}.tmp”,start);
返回名称;
}
静态公共列表文件=新列表();
静态私有void mergeClean()
{
Sort()文件;
常量int chunkSize=1*1024;//2KB
使用(var output=File.Create(“output.jpg”))
{
foreach(文件中的var文件)
{
使用(var input=File.OpenRead(File))
{
var buffer=新字节[chunkSize];
int字节读取;
而((bytesRead=input.Read(buffer,0,buffer.Length))>0)
{
输出写入(缓冲区,0,字节读取);
}
}
}
}
foreach(文件中的var文件)
{
文件。删除(文件);
}
}

您需要以正确的顺序从片段中重新组合文件-当前代码创建随机文件名,即使项目添加到文件列表中,由于片段下载完成的时间不可预测,它们也会以随机顺序添加

可能的修复方法:使用块开始偏移量作为文件名
String name=String.Format(“文件{0:D6}.tmp”,start)
的一部分,并按名称对文件进行排序,然后再将其合并回去


请注意,
{0:D6}
用于将索引填充为0,以便于按名称排序,并避免使用自然排序代码。

如何确保以正确的顺序读取/重建文件?下载每个文件后,临时名称将添加到名称数组中。mergeclean函数遍历此数组并连接文件。因此,它按数组中文件的顺序合并。但是因为它是按正确的顺序下载的。我猜它正在以正确的顺序合并@Ronbeyer在发送前创建文件的校验和,然后在下载后确认。我还注意到,您正在使用几个对象(WebResponse、Stream),这些对象不在使用块的
中。异常将使这些处于错误状态。
const int chunkSize=1*1024;//2KB
;-)好的,我接受了你的建议,现在正在对数组进行排序,然后再合并它。但问题仍然存在,它下载的图像仍然损坏。还有其他想法吗?@Chocoloco“你应该发送previous+1,而不是previous“-{0,10},{10,20},。。。而不是{0,9},{10,19},。。。