以多个块下载文件

时间:2014-09-11 14:20:25

标签: c# asp.net vb.net

我正在写一段应该以1 MB块的形式下载单个文件的代码。我使用了与此问题相同的代码:Download large file in small chunks in C#并将其转换为VB.NET。

与上一个问题相同的代码工作正常并将文件写入磁盘。但似乎第二个Web请求出现了问题。为了测试,我使用下面的VB.NET代码从https://d13yacurqjgara.cloudfront.net/users/22/screenshots/631004/attachments/53012/wallpaper-retina-cinemadisplay.png下载PNG文件。

下载的PNG似乎很好一半,剩下的图像被打乱了。

我将defaultSizechunk增加到10 MB并且文件下载完美,但似乎For / Next循环中的内容会截断或污染数据。

有什么想法会导致这种情况发生?

Private Const defaultSize As Long = 1048576
Private chunk As Long = 1048576
Private offset As Long = 0

Private Function downloadFile(ByVal url As String, ByVal filename As String) As Boolean
    Dim size As Long = getSize(url)
    Dim blockSize As Integer = Convert.ToInt32(size / defaultSize)
    Dim remainder As Integer = Convert.ToInt32(size Mod defaultSize)

    If remainder > 0 Then
        blockSize += 1
    End If

    Dim fileStream As FileStream = File.Create("C:\mydirectory\" & filename)

    For i As Integer = 0 To blockSize - 1
        If i = blockSize - 1 Then
            chunk = remainder
        End If

        Dim req As HttpWebRequest = HttpWebRequest.Create(url)
        req.Method = WebRequestMethods.Http.Get
        req.AddRange(Convert.ToInt32(offset), Convert.ToInt32(chunk + offset))
        Dim resp As HttpWebResponse = req.GetResponse()

        Using respStream As Stream = resp.GetResponseStream
            Dim buffer(4096) As Byte
            Dim bytesRead As Integer
            Do
                bytesRead = respStream.Read(buffer, 0, 4096)
                If bytesRead > 0 Then fileStream.Write(buffer, 0, bytesRead)
            Loop While bytesRead > 0
        End Using

        offset += chunk

        resp.Close()
        resp.Dispose()
    Next

    fileStream.Close()

    Return True
End Function

Private Function getSize(ByVal url As String) As Long
    Dim req As WebRequest = WebRequest.Create(url)
    req.Method = WebRequestMethods.Http.Head
    Dim resp As WebResponse = req.GetResponse
    Return Long.Parse(resp.ContentLength)
End Function

2 个答案:

答案 0 :(得分:1)

除了整理你的一些代码(我认为你将会做的事情,因为你从C#转换它),做一个小的改变让它完美地工作。

该行

offset += chunk

应该是

offset += chunk + 1

这解决了这个问题,因为offset从0开始,并且你在下一个循环中为它添加了块大小,因此你要添加一个兆字节并从那里开始。你想从最后一兆字节后面的字节继续! 我确实开始解释它是如何工作的,但我想出的例子不起作用......所以我无法解释它!也许其他人可以;这与req.AddRange有关 - 你指的是一个范围,而不是一个范围。

答案 1 :(得分:1)

代码转换的一个问题。

Convert.ToInt32(size / defaultSize)

这与C#代码中的代码相同,VB忽略分号。但是,它没有考虑“/”运算符可以在两种语言中使用整数除法返回不同值的细微差别。

变量Size和defaultSize都是长整数。在C#中分割两个整数时,结果是整数,十进制切碎而不是四舍五入。在VB中划分两个整数,结果被强制转换为十进制类型然后舍入。

/ Operator (C# Reference)

/ Operator (VB Reference)

例如,如果size和defaultSize的值为68和10。

VB

Dim result As Integer = Convert.ToInt32(size / defaultSize) 'VB result 7

C#

int result = Convert.ToInt32(size / defaultSize); // C# result 6

这可能会影响我没有追求的算法,因为声称原始代码仍然不起作用。