2014-09-11 3 views
0

Я пишу фрагмент кода, который должен загрузить один файл в 1 Мб фрагментов. Я использовал тот же код, что и в этом вопросе: Download large file in small chunks in C# и преобразовал его в VB.NET.Загрузка файла в несколько фрагментов

Код, как и предыдущий, отлично работает и записывает файл на диск. Но кажется, что во втором веб-запросе что-то пошло не так. Для тестирования я загружаю PNG-файл с https://d13yacurqjgara.cloudfront.net/users/22/screenshots/631004/attachments/53012/wallpaper-retina-cinemadisplay.png, используя код VB.NET ниже.

Загруженный PNG, кажется, в порядке, а оставшееся изображение скремблировано.

Я увеличил defaultSize и chunk до 10 МБ, и файл загрузился отлично, но кажется, что что-то в цикле 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

Прежде всего, переключите 'Option Strict' на' On'! Я только что скопировал и вставил ваш код, и было несколько жалоб от VS ... – Grim

+0

Вы действительно хотите преобразовать пример C#, поскольку автор сказал, что он все еще не работает. Я также вижу, что с ошибкой в ​​математическом преобразовании тоже. – eric1825

+0

Я отредактировал ваш заголовок. Пожалуйста, смотрите: «Если вопросы включают« теги »в их названиях?] (Http://meta.stackexchange.com/questions/19190/), где консенсус« нет, они не должны ». –

ответ

1

Помимо уборки немного кода (который я предполагаю, что вы будете делать в любом случае, так как вы конвертированы это из C#), что делает одно небольшое изменение получает это работает отлично.

Линия

offset += chunk 

должен быть

offset += chunk + 1 

Это решает вопрос, потому что offset начинается с 0, и вы добавляете размер куска к нему на следующем цикле, поэтому вы» повторное добавление мегабайта и начало работы там. Вы хотите продолжать с байта после последнего мегабайта! Я начал объяснять, как это работает, но пример, который я придумал, не работает ... поэтому я не могу это объяснить! Может быть, кто-то другой может; это связано с req.AddRange - вы указываете диапазон, а не итог.

1

Одна проблема при конвертации кода.

Convert.ToInt32(size/defaultSize) 

Это тот же код в коде C# и VB, игнорирующий точку с запятой. Однако он не учитывает нюанс, что оператор «/» может возвращать другое значение с целым делением на двух языках.

Размер переменной и defaultSize являются длинными целыми числами. При делении двух целых чисел на C# результат представляет собой целое число, десятичное нарезанное и не округленное. В VB, делящем два целых числа, результат принуждается к десятичному типу, затем округляется.

/ Operator (C# Reference)

/ Operator (VB Reference)

Например, если значения для размера и 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 

Как это может повлиять на алгоритм, который я не преследовал, учитывая, что исходный код, как утверждается, все еще не работает.

+1

Если вы хотите получить тот же результат в VB как C# для целочисленного деления, вы можете использовать обратную косую черту \ как оператор вместо оператора прямой косой черты/деления. Обратная косая черта возвращает целочисленный результат в VB, при этом оставшаяся часть отбрасывается. – eric1825

+0

Спасибо! Хотя основной проблемой было то, что смещение не было правильным, этот надзор в преобразовании кода определенно будет следующей проблемой. Используя оба предложения, код, похоже, работает безупречно. – Zishan

Смежные вопросы