Outside the sub? Why do you need them there?I declared the filestreams outside of the sub
That is also not necessary, you already have the information if operation was cancelled or errored, if neither then operation logically must be complete.in the RunWorkerCompleted function, I compare size of the old and new files and made sure the progressbar received a value of 100 upon success
Not much, but it would preserve system resources better. Let's say as illustration you copy a 5mb file and the operation takes 5 seconds, which amounts to 1000kb per second. With progress every 1kb that makes 5000 percentage calculations and reports, 500 per second, each percentage would be posted 50 times. It should go without saying this is lots of redundant information for user, and lots of operations the program has no need to process. If you store previous calculated percentage you could post only each time percentage changes, which would be exactly 100 times. Still that would mean lots of calculations and 20 progress reports per second, which in my opinion is insignificant for user. If progress was updated once per second only 5 reports would be made here (20%,40%,60% etc). And if we imagine a file 10 times that size then progress would be posted for 2%,4%,6% each second. When updating the ProgressBar with a larger value span for example from 20% to 40% it animates the change, and it would appear as a dynamic change to the user. The Progressbar also has animation when value doesn't change, at least in Vista, so user can see something is happening even if should take longer time between changes.Do you think it is the monitoring of the byte progress that makes the action slower?
Because if I declare them inside the sub, Intellisense tells me, via little green squiggly lines in sr and sw in the Finally clause, "variable sr has been used before it has assigned a value. A null reference exception could result at runtime." If I was more sure of my programming skills, I might think I could ignore the warnings given by intellisense.Outside the sub? Why do you need them there?
Then it is safe to assume the integrity of the copied file?If operation was cancelled or errored, if neither then operation logically must be complete.
You can assign Nothing to those variables initially to prevent that warning. Also remember later that these variables might actually be null references if no object was assigned to them.Because if I declare them inside the sub, Intellisense tells me, via little green squiggly lines in sr and sw in the Finally clause, "variable sr has been used before it has assigned a value. A null reference exception could result at runtime." If I was more sure of my programming skills, I might think I could ignore the warnings given by intellisense.
Absolutely, if there was a problem an exception would be thrown.Then it is safe to assume the integrity of the copied file?
Declare the array the size of your decided buffer size, not the size of the file. Remember that space is allocated for an array whether it is used or not.Dim byteData(len) As byte
FileStream.Read MethodI might try this read/write part, but what I have so far isn't right.
If i = CopyBufferSize or len-i < CopyBufferSize then
Private Sub FileCopyWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles FileCopyWorker.DoWork
whattempdestinationfile = GetDirFromPath(whatdestinationfile) & "temp"
dim fi As Fileinfo = nothing
dim sr As FileStream = nothing
dim sw As filestream = nothing
Const CopyBufferSizeAs Integer = 64 * 1024
Try
MessengerLogger.Info("Please wait whilst I upload " & whatoriginationfile)
fi = New IO.FileInfo(whattempdestinationfile)
sr = New IO.FileStream(whatoriginationfile, IO.FileMode.Open) 'source file
sw = New IO.FileStream(whattempdestinationfile, IO.FileMode.Create) 'target file, defaults overwrite
Dim len As Long = sr.Length - 1 'starts at 0, we need to offset
Dim byteData(CopyBufferSize) As byte
Dim i As long
Dim bytesRead As long
For i = 0 To len
If FileCopyWorker.CancellationPending Then
FileStatus = false
MessengerLogger.Warn("You cancelled the transfer at: " & progress & "%.")
Exit For
End If
If i = CopyBufferSize or len-i < CopyBufferSize then
bytesRead = sr.Read(byteData, 0, CopyBufferSize)
'sr.Read(byteData, 0, len)
sw.Write(byteData, 0, bytesRead)
End if
If i = len then FileStatus = true
'This if clause is designed only to monitor for the progress bar progress
If i Mod 100000 = 0 Then 'only update UI every 100 Kb copied
progress = i * 100 / len
FileCopyWorker.ReportProgress(progress)
Application.DoEvents()
End If
Next
Catch ex As Exception
MessengerLogger.Error("There was an error in the procedure: " & ex.Message & " :CopyFileWithProgress.")
FileStatus = false
Finally
If Not (sr is Nothing) then sr.close
If Not (sw is Nothing) then sw.close
End Try
End Sub
Private Sub FileCopyWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles FileCopyWorker.DoWork
whattempdestinationfile = GetDirFromPath(whatdestinationfile) & "temp"
dim fi As Fileinfo = nothing
dim sr As FileStream = nothing
dim sw As filestream = nothing
Const CopyBufferSize As Integer = 64 * 1024
Try
MessengerLogger.Info("Please wait whilst I upload " & whatoriginationfile)
fi = New IO.FileInfo(whattempdestinationfile)
sr = New IO.FileStream(whatoriginationfile, IO.FileMode.Open) 'source file
sw = New IO.FileStream(whattempdestinationfile, IO.FileMode.Create) 'target file, defaults overwrite
Dim len As Long = sr.Length - 1 'starts at 0, we need to offset
Dim byteData(CopyBufferSize) As byte
Dim bytesRead As long
Do
If FileCopyWorker.CancellationPending Then
FileStatus = false
MessengerLogger.Warn("You cancelled the transfer at: " & progress & "%.")
Exit Do
End If
bytesRead = sr.Read(byteData, 0, CopyBufferSize)
sw.Write(byteData, 0, bytesRead)
If sw.Position Mod CopyBufferSize= 0 Then
progress = sw.Position / len * 100
FileCopyWorker.ReportProgress(progress)
Application.DoEvents()
End If
If bytesRead = 0 then
FileStatus = true
Exit Do
End If
Loop
Catch ex As Exception
MessengerLogger.Error("There was an error in the procedure: " & ex.Message & " :CopyFileWithProgress.")
FileStatus = false
Finally
If Not(sr is Nothing) then sr.close
If Not(sw is Nothing) then sw.close
End Try
End Sub
Local file copy may very well be that fast, just a few comments:tried it on a 37mb file and it was so fast the progressbar didn't even have time to work.
Never used.dim fi As Fileinfo = nothing
fi = New IO.FileInfo(whattempdestinationfile)
Just one byte off. Will only be a problem if file size is 1 byte. DivideByZeroException.Dim len As Long = sr.Length - 1
progress = sw.Position / len * 100
Here you declare the array one byte larger than you intend to and ever use. Not a big deal, but it looks like you don't know arrays or VB syntax too well.Dim byteData(CopyBufferSize) As byte
Since you read CopyBufferSize each time this will always be true, so you are in effect reporting progress each iteration. 37gb / 64kb = 578 or so, meaning you report each percentage number 5-6 times in this case.If sw.Position Mod CopyBufferSize= 0 Then
Yes, I know that, actually :smile:; I tried a few other things in that spot, but that seemed the best,as most of the files I will be dealing with are 16mb+, but I'd like to think of something better.Since you read CopyBufferSize each time this will always be true, so you are in effect reporting progress each iteration. 37gb / 64kb = 578 or so, meaning you report each percentage number 5-6 times.
Well, in my RunWorkerCompleted function, I need to know whether the copy-process failed or not. If the user cancelled the operation, I want the progressbar to stop at the percentage where it stopped. If the cancel operation returns false, then the RunWorkerCompleted will provide the right notifications for the user.Using a FileStatus boolean variable give no additional value in my opinion. What you should do with CancellationPending is to set e.Cancel and exit, from there you have all information you need in RunWorkerCompleted event to report completion status.
Private Sub FileCopyWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles FileCopyWorker.RunWorkerCompleted
If filestatus then
'MessengerLogger.Info("Almost there...")
File.Move(whattempdestinationfile, whatdestinationfile)
MessengerLogger.Info(msg_finished)
whatprogressbar.Value = 100
'MakeThreadedNotifications() 'that is, send an email to notify someone
Else
MessengerLogger.Warn(msg_toobad)
File.Delete(whattempdestinationfile)
End If
whatstartbutton.Enabled = True
whatcancelbutton.Enabled = False
End Sub
You are quite right. I am used to coding in BCX, powerpro, and autohotkey. This is my first full-fledged vb.net application, although I've hacked through a bit of asp.net. Aside from that, it is one of my common mistakes to overrun arrays... One language starts them a 1, another starts at 0, and, in order to keep track I have to be in a routine. But I like .net - it is so powerful. I think I am getting a little better, however (with thanks to certain people...)...it looks like you don't know arrays or VB syntax too well.
A couple of reasons, actually, first, I find the casing to be an extra thing to type and keep track of, so I often use all lower case letters. Then I wish I had them camelcased because it looks nicer and is easier to read. Then I can't remember which letters were camelcased. Besides that, VS doesn't seem to care, not like Javascript. BCX is case-sensitive, so I use mostly all lowercase. But although VS doesn't seem to care much, it "corrects" my typing most, but not all of the time, which results in the inconsistency.Why is much of the code casing wrong by the way?
Which information is known and available without that variable.Well, in my RunWorkerCompleted function, I need to know whether the copy-process failed or not.
I was not commenting that, I was commenting the fact that you have the computer frequently check some logic that will always equate to True in your code.progress = sw.Position / len * 100
Actually, this is used - it provides the progress value for the progressbar.
fair enough, I was just pointing out the minor mistakere said:...it looks like you don't know arrays or VB syntax too well.
I was actually referring to code keywords that VS formats automatically. You were giving the impression of posting unresolved "notepad" code.re said:Why is much of the code casing wrong by the way?
How is that? You mentioned using "e" of the worker. I don't get that, however. I admit, I am still struggling with understanding the backgroundworker.Which information is known and available without that variable.
All events that conform to the design guidelines have two parameters, 'sender' which refers to the class instance that raised the event, and 'e' that is a EventArgs derive and provides additional event information. EventArgs class has no properties, but if you see an event that uses a derived class, for example DoWorkEventArgs, it always has additional properties that is relevant to the event handling.You mentioned using "e" of the worker. I don't get that
I don't know why that is slow for you, it should only result in a simple request to target computer to remap its file table. That is what is happening when I do that, the operation only takes a few millisecond to complete.I have been using file.move for this, but that takes nearly as long as copying it
Debug.Print(e.Result.ToString)
I recommend you read the documentation for that class, any part of if you want to know about: BackgroundWorker ClassI am still struggling with understanding the backgroundworker
Read for example the DoWork event topic.Can I set e to something manually, or is it automatic?