Reputation: 23
I am using the Google Drive API to download files from Google Drive, it works fine, but I want to add pause and resume functionality.
I am trying to achieve this for 3 days of researching and reading google instructions but I didn't got it to work.
The downloaded file is always corrupted
This is my code:
Const KB As Integer = &H400
Dim ChunkSize As Integer = 256 * KB
Dim FileRequest = Service.Files.Get(fileid)
FileRequest.Fields = "createdTime,id,name,originalFilename,size,mimeType"
Dim Results = FileRequest.Execute()
Dim Size As Long = Results.Size
Dim client = FileRequest.Service.HttpClient
Using file = New FileStream(FilePath, FileMode.CreateNew, FileAccess.ReadWrite)
file.SetLength(Size)
Dim chunks = (Size / ChunkSize) + 1
For index As Long = 0 To chunks - 1
Dim request = FileRequest.CreateRequest()
Dim from = index * ChunkSize
Dim [to] = from + ChunkSize - 1
request.Headers.Range = New RangeHeaderValue(from, [to])
Dim response = Await client.SendAsync(request)
If response.StatusCode = Net.HttpStatusCode.PartialContent OrElse response.IsSuccessStatusCode Then
Using stream = Await response.Content.ReadAsStreamAsync()
file.Seek(from, SeekOrigin.Begin)
Await stream.CopyToAsync(file)
End Using
End If
Next
End Using
I also tried this code:
Dim FileRequest = Service.Files.Get(fileid)
FileRequest.Fields = "createdTime,id,name,originalFilename,size,mimeType"
Dim Results = FileRequest.Execute()
Dim FileDownloadSize As Long = Results.Size
Const KB As Integer = &H400
Dim ChunkSize As Integer = 256 * KB
Dim Stream As FileStream = New FileStream(FilePath, FileMode.Create, FileAccess.ReadWrite)
Dim Request = Service.Files.Get(fileid)
Dim chunks = (FileDownloadSize / ChunkSize) + 1
Dim from = 0
Dim client = Request.Service.HttpClient
While from < FileDownloadSize
Dim [to] = from + ChunkSize
Dim GetRequest = Request.CreateRequest()
GetRequest.Headers.Range = New RangeHeaderValue(from, [to])
Dim response = Await client.SendAsync(GetRequest)
If (response.StatusCode = Net.HttpStatusCode.PartialContent Or response.IsSuccessStatusCode) Then
Using respstream = Await response.Content.ReadAsStreamAsync()
Stream.Seek(from, SeekOrigin.Begin)
Await respstream.CopyToAsync(Stream)
End Using
End If
from = [to] + 1
End While
Stream.Dispose()
So What i am missing !
Upvotes: 0
Views: 126
Reputation: 23
Finally solved it myself!
I was downloading the file meta data not it's content and i wasn't reading the downloaded bytes to resume interrupted download
I'll leave it here for anyone looking for
Function getCurrRowIndex()
Try
Dim row = From EachRow As DataGridViewRow In DGV.Rows
Where EachRow.Cells("GDrive_ID").Value = Me.CurrFileID
Select EachRow
Dim rowIndex = row.First.Index
Return rowIndex
Catch ex As Exception
Return -1
End Try
End Function
Async Sub DownloadFile(fileid as String , FilePath as String)
Try
Const KB As Integer = &H400
Dim chunkSize = 1024 * KB
Dim fileRequest = Service.Files.[Get](fileid)
fileRequest.Fields = "*"
fileRequest.SupportsAllDrives = True
Dim fileResponse = fileRequest.Execute()
Dim client = fileRequest.Service.HttpClient
Dim size = fileResponse.Size
Dim DownloadedBytesBefore As Long = 0
If IO.File.Exists(FilePath) Then ' Check if the same file downloaded before and get the download bytes to start from it
Dim myFile As New FileInfo(FilePath)
DownloadedBytesBefore = myFile.Length
End If
Using file = New FileStream(FilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite)
If (size / 1024 / 1024) > 150 Then
Dim chunks, from
chunks = ((size - DownloadedBytesBefore) / chunkSize) + 1
For index As Long = 0 To chunks - 1
from = DownloadedBytesBefore + (index * chunkSize)
Dim [to] = from + chunkSize
Dim range = New System.Net.Http.Headers.RangeHeaderValue(from, [to])
Dim request = fileRequest.CreateRequest()
request.Headers.Range = range
Dim response = Await client.SendAsync(request)
If response.StatusCode <> Net.HttpStatusCode.PartialContent AndAlso Not response.IsSuccessStatusCode Then
Console.WriteLine(response.ToString())
Continue For
End If
If Not IsNothing(DGV) Then
Dim rowIndex As Integer = getCurrRowIndex()
If DGV("Status", rowIndex).Value <> "Pausing" Then
DGV("Status", rowIndex).Value = "Downloading"
DGV("BytesDownloaded", rowIndex).Value = Math.Round(CDbl(from / 1024), 2) & " Kb / " & Math.Round(CDbl(size / 1024), 2) & " Kb"
Dim percentage As Double = (from / size * 100)
DGV("Progress", rowIndex).Value = Math.Round(percentage, 2) & "%"
Else
DGV("Status", rowIndex).Value = "Paused"
While DGV("Status", rowIndex).Value = "Paused"
Threading.Thread.Sleep(1000)
End While
End If
End If
Console.WriteLine($"ChunkIndex: {index}; File Size: {size}; Bytes Downloaded: {from} ({Convert.ToDecimal(from) / (1024D * 1024D)}) MB; ")
file.Seek(from, SeekOrigin.Begin)
Await fileRequest.DownloadRangeAsync(file, range)
Next
Else
AddHandler fileRequest.MediaDownloader.ProgressChanged, AddressOf ProgChanged
fileRequest.DownloadWithStatus(file)
End If
If Not IsNothing(DGV) Then
Dim rowIndex As Integer = getCurrRowIndex()
DGV("Status", rowIndex).Value = "Completed"
DGV("Progress", rowIndex).Value = "100%"
DGV("BytesDownloaded", rowIndex).Value = Math.Round(CDbl(size / 1024 / 1024), 2) & " Mb / " & Math.Round(CDbl(size / 1024 / 1024), 2) & " Mb"
End If
End Using
Catch ex As Exception
If Not IsNothing(DGV) Then
Dim rowIndex As Integer = getCurrRowIndex()
DGV("Status", rowIndex).Value = "Failed"
End If
End Try
End Sub
Upvotes: 2