我正在写一段应该以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似乎很好一半,剩下的图像被打乱了。
我将defaultSize
和chunk
增加到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
答案 0 :(得分:1)
除了整理你的一些代码(我认为你将会做的事情,因为你从C#转换它),做一个小的改变让它完美地工作。
该行
offset += chunk
应该是
offset += chunk + 1
这解决了这个问题,因为offset
从0开始,并且你在下一个循环中为它添加了块大小,因此你要添加一个兆字节并从那里开始。你想从最后一兆字节后面的字节继续!
我确实开始解释它是如何工作的,但我想出的例子不起作用......所以我无法解释它!也许其他人可以;这与req.AddRange
有关 - 你指的是一个范围,而不是一个范围。
答案 1 :(得分:1)
代码转换的一个问题。
Convert.ToInt32(size / defaultSize)
这与C#代码中的代码相同,VB忽略分号。但是,它没有考虑“/”运算符可以在两种语言中使用整数除法返回不同值的细微差别。
变量Size和defaultSize都是长整数。在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
这可能会影响我没有追求的算法,因为声称原始代码仍然不起作用。