在多个块中下载文件

本文关键字:下载 文件 | 更新日期: 2023-09-27 18:21:28

我正在编写一段代码,该代码应该下载1MB块中的单个文件。我使用了与这个问题中相同的代码:在C#中下载大块的大文件,并将其转换为VB.NET.

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

下载的PNG似乎已经完成了一半,剩下的图像被打乱了。

我将defaultSizechunk增加到10MB,文件下载非常完美,但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

在多个块中下载文件

除了整理一些代码(我想你无论如何都会这样做,因为你是从C#转换过来的),做一个小的更改就能完美地工作。

线路

offset += chunk

应该是

offset += chunk + 1

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

关于代码转换的一个问题。

Convert.ToInt32(size / defaultSize)

这是相同的代码,在C#代码和VB中忽略分号。然而,它没有考虑到在两种语言中,"/"运算符可以通过整数除法返回不同的值这一细微差别。

变量Size和defaultSize都是长整数。当在C#中对两个整数进行除法时,结果是一个整数,小数被截断而不取整。在VB中,将两个整数除法,结果被强制为十进制,然后四舍五入。

/操作员(C#参考)

/操作员(VB参考)

例如,如果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

这可能会对我没有追求的算法产生怎样的影响,因为最初的代码被声称仍然不起作用。