Check if downloaded file exists by comparing it's file size - vb.net

Is there a way to check a downloaded file is already exists by comparing it's file size?
Below is my download code.
Private Sub bgw_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
Dim TestString As String = "http://123/abc.zip," & _
"http://abc/134.zip,"
address = TestString.Split(CChar(",")) 'Split up the file names into an array
'loop through each file to download and create/start a new BackgroundWorker for each one
For Each add As String In address
'get the path and name of the file that you save the downloaded file to
Dim fname As String = IO.Path.Combine("C:\Temp", IO.Path.GetFileName(add))
My.Computer.Network.DownloadFile(add, fname, "", "", False, 60000, True) 'You can change the (False) to True if you want to see the UI
'End If
Next
End Sub

The size of a local file can be determined using the File or FileInfo class from the System.IO namespace. To determine the size of a file to be downloaded by HTTP, you can use an HttpWebRequest. If you set it up as though you were going to download the file but then set the Method to Head instead of Get you will get just the response headers, from which you can read the file size.
I've never done it myself, or even used an HttpWebRequest to download a file, so I'm not going to post an example. I'd have to research it and you can do that just as easily as I can.
Here's an existing thread that shows how it's done in C#:
How to get the file size from http headers
Here's a VB translation of the code from the top answer:
Dim req As System.Net.WebRequest = System.Net.HttpWebRequest.Create("https://stackoverflow.com/robots.txt")
req.Method = "HEAD"
Using resp As System.Net.WebResponse = req.GetResponse()
Dim ContentLength As Integer
If Integer.TryParse(resp.Headers.Get("Content-Length"), ContentLength)
'Do something useful with ContentLength here
End If
End Using
A better practice would be to write this line:
req.Method = "HEAD"
like this:
req.Method = System.Net.WebRequestMethods.Http.Head

Related

Upload and replace the same image file if it already exist

I have a picturebox named PB_Company_Logo and I have a button named btn_Save and within this button I have this function which saves the image in PB_Company_Logo to current_directory/images
Public Sub save_PB(PB_Name As PictureBox)
Dim filename As String = "company_logo.png"
Dim path As String = Directory.GetCurrentDirectory() & "\images"
Dim filename_path As String = System.IO.Path.Combine(path, filename)
If (Not System.IO.Directory.Exists(path)) Then
System.IO.Directory.CreateDirectory(path)
PB_Name.Image.Save(filename_path)
Else
PB_Name.Image.Save(filename_path)
End If
End Sub
The problem is, there are cases where the user will upload a new company_logo.png. I want the system to treat the uploading of new image as replacing the former company_logo.png.
I think the error in this line of code means that the file is currently in used (locked) and therefore cannot be replaced.
Else
PB_Name.Image.Save(filename_path)
End If
When you load a pictureBox control with an image file the ide (vs) puts a lock on the file. This happens when you set the image property of the pictureBox control to a file at design time.
You can use the FileStream object.
Example:
Dim fs As System.IO.FileStream
' Specify a valid picture file path on your computer.
fs = New System.IO.FileStream("C:\WINNT\Web\Wallpaper\Fly Away.jpg",
IO.FileMode.Open, IO.FileAccess.Read)
PictureBox1.Image = System.Drawing.Image.FromStream(fs)
fs.Close()
After you have done the workaround you can then use the System.IO.File.Exists(img) namespace to check wether or not a picture exists.
Example: This checks if the image passed through already exists and if it does then it will replace it.
Dim imageStr As String = "~/images/name.jpg"
If System.IO.File.Exists(imageStr) Then
Image1.ImageUrl = "~/images/name.jpg"
End If

Get file size before download it in vb

I have been working on a web browser in visual basic..Now,what I want to do is to the get file size before download it and when I click download I want to to get the number of the alrady downloaded Mbs(watch the picture)
Thank's for help!
I've done some research, and this would probably be the most simple and "cleanest" way of getting a download's size (in bytes):
Public Function GetDownloadSize(ByVal URL As String) As Long
Dim r As Net.WebRequest = Net.WebRequest.Create(URL)
r.Method = Net.WebRequestMethods.Http.Head
Using rsp = r.GetResponse()
Return rsp.ContentLength
End Using
End Function
Credit to Reed Kimble, who told me to dispose the WebResponse in my initial MSDN question.
The above code will read the response headers of the file, rather than reading the body of it. This means that the file does not require to get downloaded, just to check it's size.
This is the reason to why some codes requires the file to actually get downloaded at first; they're reading the file's body rather than it's headers.
Hope this helps!
Use the WebClient ResponseHeaders:
Public Shared Function GetFileSize(url As String) As Long
Using obj As New WebClient()
Using s As Stream = obj.OpenRead(url)
Return Long.Parse(obj.ResponseHeaders("Content-Length").ToString())
End Using
End Using
End Function
Request file size before download it
The WebClient's DownloadProgressChanged event's args contains the property TotalBytesToRecieve. That tells you how many bytes the file you're downloading is.
Not the prettiest way, but if you want to get the size of the file before downloading you can start downloading the file then immediately cancel it:
Dim DownloadSize As Long
Private Sub CheckDownloadSize(ByVal URL As String)
WebClient.DownloadFile(URL, IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.Temp, "tempdownload.tmp"))
End Sub
Private WithEvents WebClient As New WebClient
Private Sub WebClient_DownloadProgressChanged(ByVal sender As Object, ByVal e As System.Net.DownloadProgressChangedEventArgs) Handles WebClient.DownloadProgressChanged
DownloadSize = e.TotalBytesToReceive
WebClient.CancelAsync()
End Sub
Otherwise, just remove the .CancelAsync() line.

Set "client_updated_time" when uploading file to OneDrive

I have nearly completed a basic OneDrive interface, and am able to handle creating and writing folders, files, and so forth. The last element to get working is to update a file's date/time stamp to match that of the local (originating) file.
When I drop a file via the browser interface, the file's date/time stamp shows correctly in the view. This is reflected in the "client_updated_time" when I read the file's properties later in my application. Clear enough.
However, I cannot find any way to update this field programmatically from within my application. I am using the following code, to no avail. I have a valid _accessToken value, a valid fileId for the new file, and the call results always indicates success.
The "name" and "updated_time" elements are just in there to see if anything happens, and the file will indeed rename if I mangle the fileName variable a bit. I didn't expect the "updated_time" to updated, but it seems to me that the "client_updated_time" element should work.
Using fiddler, it appears that the browser-based interface (java?) opens a session, sends the file over, and then in the close-session call uses a header entry labelled "X-Last-Modified-ISO8601" to set the file's date-time stamp. However, using the REST interface, I cannot find any examples of this. The documentation for setting file properties mentions renaming only (which works in this code).
Any feedback on how to accomplish setting "client_updated_time" with REST calls would be much appreciated!
Here's the relevant code:
Private _liveURL As String = "https://apis.live.net/v5.0/"
Private Sub AddAuthorizationHeader(hc As HttpClient, authorization As String)
If Len(authorization) > 0 Then
hc.DefaultRequestHeaders.Authorization = New Headers.AuthenticationHeaderValue("Bearer", authorization)
End If
End Sub
Public Function WebPUT(uri As String, contentType As String, authorization As String, data As String) As String
Dim response As String = String.Empty
Try
Dim hc As New HttpClient()
Dim content As New Http.StringContent(data, System.Text.Encoding.UTF8, contentType)
AddAuthorizationHeader(hc, authorization)
Using r = hc.PutAsync(uri, content).Result
response = r.Content.ReadAsStringAsync.Result
End Using
Catch ex As Exception
' fake it
response = "{""error"": {""code"": ""invalid_request"", ""message"": """ + ex.Message + """}}"
End Try
Return response
End Function
Private Function UpdateFileDateTime(fileId As String, fileName As String, fileDt As String) As Boolean
Dim response As Boolean = False
Dim wr As String = WebHelper.WebPUT(_liveURL + fileId, "application/json", _accessToken, "{ ""name"": """ + fileName + """, ""updated_time"": """ + fileDt + """, ""client_updated_time"": """ + fileDt + """ }")
'... parse wr for response
Return response
End Function
Based on the file object reference, that field is read-only via the REST API: http://msdn.microsoft.com/en-us/library/dn631834.aspx

How can I fetch the last-modified value of a remote file?

I'd like to know the last-modifed date of a remote file (defined via url).
And only download it, if it's newer than my locally stored one.
I managed to do that for local files, but can't find a solution to do that for remote files (without downloading them)
working:
Dim infoReader As System.IO.FileInfo = My.Computer.FileSystem.GetFileInfo("C:/test.txt")
MsgBox("File was last modified on " & infoReader.LastWriteTime)
not working:
Dim infoReader As System.IO.FileInfo = My.Computer.FileSystem.GetFileInfo("http://google.com/robots.txt")
MsgBox("File was last modified on " & infoReader.LastWriteTime)
I'd love to have a solution which will only have to download the headers of a file
You can use the System.Net.Http.HttpClient class to fetch the last modified date from the server. Because it's sending a HEAD request, it will not fetch the file contents:
Dim client = New HttpClient()
Dim msg = New HttpRequestMessage(HttpMethod.Head, "http://google.com/robots.txt")
Dim resp = client.SendAsync(msg).Result
Dim lastMod = resp.Content.Headers.LastModified
You could also use the If-Modified-Since request header with a GET request. This way the response should be 304 - Not Modified if the file has not been changed (no file content sent), or 200 - OK if the file has been changed (and the contents of the file will be sent in the response), although the server is not required to honor this header.
Dim client = New HttpClient()
Dim msg = New HttpRequestMessage(HttpMethod.Get, "http://google.com/robots.txt")
msg.Headers.IfModifiedSince = DateTimeOffset.UtcNow.AddDays(-1) ' use the date of your copy of the file
Dim resp = client.SendAsync(msg).Result
Select Case resp.StatusCode
Case HttpStatusCode.NotModified
' Your copy is up-to-date
Case HttpStatusCode.OK
' Your copy is out of date, so save it
File.WriteAllBytes("C:\robots.txt", resp.Content.ReadAsByteArrayAsync.Result)
End Select
Note the use of .Result, since I was testing in a console application - you should probably await instead.
If the server offers it, you can get it through the HTTP header Last-Modified property. But your still stuck at downloading the full file.
You could get it through FTP.
See if the server allows you to see the list of files in a folder.
If the website offer the date somewhere that you could pull through screen scrapping.
I know this is a little bit old question but, there's still a better answer.
Dim req As WebRequest = HttpWebRequest.Create("someurl")
req.Method = "HEAD"
Dim resp As WebResponse = req.GetResponse()
Dim remoteFileLastModified As String = resp.Headers.Get("Last-Modified")
Dim remoteFileLastModifiedDateTime As DateTime
If DateTime.TryParse(remoteFileLastModified, remoteFileLastModifiedDateTime) Then
MsgBox("Date Last Modified:" + remoteFileLastModifiedDateTime.ToString("d MMMM yyyy dddd HH:mm:ss"))
Else
MsgBox("could not determine")
End If

GZipstream cuts off data from original file when decompressing

For a long time I have been trying to debug why my parsing counts were off when downloading files to be parsed and been made to look really dumb about this. I did some debugging and found that the file I download when trying to decompress using GZipStream shows that it misses data from the original file. Here is my code for decompressing:
Using originalFileStream As FileStream = fileItem.OpenRead()
Dim currentFileName As String = fileItem.FullName
Dim newFileName = currentFileName.Remove(currentFileName.Length - fileItem.Extension.Length)
newFile = newFileName
Using decompressedFileStream As FileStream = File.Create(newFileName)
Using decompressionStream As GZipStream = New GZipStream(originalFileStream, CompressionMode.Decompress)
decompressionStream.CopyTo(decompressedFileStream)
Console.WriteLine("Decompressed: {0}", fileItem.Name)
decompressionStream.Close()
originalFileStream.Close()
End Using
End Using
End Using
Now what I do is return the newfile to the calling function and read the contents from there:
Dim responseData As String = inputFile.ReadToEnd
Now pasting the url in the browser and downloading from there and then opening using winrar I can see the data is not the same. Now this does not happen all the time as some files parse and decompress correctly. Each downloaded file has check counter to compare how many posts I am supposed to be parsing from it and that triggered me to see the mismatch in counts.
EDIT
Here is what I found in addition. If I read the problem file (as I said that only some files happen this way) by individual lines I will get all the data:
Dim rData As String = inputFile.ReadLine
If Not rData = "" Then
While Not inputFile.EndOfStream
rData = inputFile.ReadLine + vbNewLine + rData
End While
getIndividualPosts(rData)
End If
Now if I try to read an individual line from a file that is not problematic it will return nothing and so I will have to readtoEnd. Can anyone explain this odd behavior and is it related to the GZIPSTREAM or some error in my code.