Can't Multi Download With WebClient - vb.net

I know this question has been asked before, but I have a special way I want to download the files through a webclient, I want to download each file at a time through a Do While statement, but it just adds the file to download and moves on to the next task that also downloads another file so it cancels each other out and crashes the application.
Private Function StartDownloads()
Dim wc As New WebClient
AddHandler wc.DownloadProgressChanged, AddressOf DownloadProgressChanged
AddHandler wc.DownloadFileCompleted, AddressOf DownloadFileCompleted
Dim delimiterChars As Char() = {"+"c}
Dim words As String() = RichTextBox1.Text.Split(delimiterChars)
Dim i As Integer = 1
Do While (i < words.Length)
Dim delimiterChars1 As Char() = {"|"c}
Dim words1 As String() = words(i).Split(delimiterChars1)
Dim name As String = words1(0)
Dim fileurl As String = words1(2)
ToolStripStatusLabel1.Text = "Downloading " & name & ":"
wc.DownloadFileAsync(New System.Uri(fileurl), Path.GetTempPath() & "\" & name)
i = (i + 1)
Loop
End Function
AND
Private Sub DownloadProgressChanged(sender As Object, e As DownloadProgressChangedEventArgs)
ProgressBar1.Value = e.ProgressPercentage
ToolStripStatusLabel2.Text = String.Format("{0} MB's / {1} MB's",
(e.BytesReceived / 1024D / 1024D).ToString("0.00"),
(e.TotalBytesToReceive / 1024D / 1024D).ToString("0.00"))
End Sub
So basically in the Do While statement it starts the download then continues without waiting for the download to finish and then downloads both at once, which then crashes the program/interferes with the labels displaying the download name, the reason this is a different question from others is I need it to specify the download name as I can't do with other tutorials, by adding the downloads to a list...
So if anyone can help me make the Do While statement wait for the download to finish then continue with the next without loosing the file name and stuff like that, please give me some tips, thanks!
I know that DownloadFile waits for the download to finish then continues, but I need it to show download progress and download bytes and stuff like that...
P.S. Sorry if this is confusing as it's hard to explain, thanks.

By adding await wc.DownloadFileTaskAsync(...), it worked perfectly

Related

Do...Loop starts too quickly, how to brake it?

With my program, user have to download and save csv files to two different specific directories. Unfortunately automatic downloading not possible. To download file I use command WebBrowser1.Navigate(url), which run php script on the target web page and after one second webBrowser ask path where I or user want to download file. After that again button click and .Navigate to download second one.
But I have to be sure, that user had download file exactly to the specific directory and first, I want to check if file exists there. And here problems are starts. Because of small delay before "Save" possibility, program run immediately Do...Loop process and "Save" window doesn't even come. Also I tried to use thread.sleep, but it doesn't help. Because it immediately go to sleep and "save" window have not time to present. After sleep it immediately starts Do...Loop process.
Is here some other instruments to say to my program, that it wait a little and continue to run code after user "Save" file?
Here is My code:
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim kraporttila As String
Dim dt1 As Date = DateTimePicker1.Value
Dim dt2 As Date = DateTimePicker2.Value
Dim faa As String = dt1.ToString("yyyy-MM-dd")
Dim fla As String = dt2.ToString("yyyy-MM-dd")
Dim ddla As String = dt2.ToString("MM.yy")
Dim kuitti As Uri = New Uri("https:url/kuitti.php?faa=" & faa & "&fla=" & fla & "&fk_e=&fa_e=&fm=&ftil=&kuittiexportcsv=Lataa%CSV")
WebBrowser1.Navigate(kuitti)
Button2.Visible = False
Do While
If System.IO.File.Exists(kraporttila) = True Then
Button3.Text = "Lataa maksuvirheet"
Button3.Visible = True
Label3.Text = "Nyt lataa maksuviheet ja tellenna kansioon ""C:\Users\Ivan\" & ddla & "\Laskutukset ja Maksuvirheet\Maksuvirheet"""
Exit Do
Else
Continue Do
End If
Loop
End Sub

Loop to print text files is skipping some files(randomly, it seems)

I have a VB.NET program which lists some text files in a directory and loops through them. For each file, the program calls notepad.exe with the /p parameter and the filename to print the file, then copies the file to a history directory, sleeps for 5 seconds(to allow notepad to open and print), and finally deletes the original file.
What's happening is, instead of printing every single text file, it is only printing "random" files from the directory. Every single text file gets copied to the history directory and deleted from the original however, so I know that it is definitely listing all of the files and attempting to process each one. I've tried adding a call to Thread.Sleep for 5000 milliseconds, then changed it to 10000 milliseconds to be sure that the original file wasn't getting deleted before notepad grabbed it to print.
I'm more curious about what is actually happening than anything (a fix would be nice too!). I manually moved some of the files that did not print to the original directory, removing them from the history directory, and reran the program, where they DID print as they should, so I know it shouldn't be the files themselves, but something to do with the code.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim f() As String = ListFiles("l:\", "997")
Dim i As Integer
Try
For i = 0 To f.Length - 1
If Not f(i) = "" Then
System.Diagnostics.Process.Start("Notepad.exe", " /p l:\" & f(i))
My.Computer.FileSystem.CopyFile("l:\" & f(i), "k:\" & f(i))
'Thread.Sleep(5000)
Thread.Sleep(10000)
My.Computer.FileSystem.DeleteFile("l:\" & f(i))
End If
Next
'Thread.Sleep(5000)
Thread.Sleep(10000)
Catch ex As Exception
End Try
End Sub
Public Function ListFiles(ByVal strFilePath As String, ByVal strFileFilter As String) As String()
'finds all files in the strFilePath variable and matches them to the strFileFilter variable
'adds to string array strFiles if filename matches filter
Dim i As Integer = 0
Dim strFileName As String
Dim strFiles(0) As String
Dim strExclude As String = ""
Dim pos As Integer = 0
Dim posinc As Integer = 0
strFileName = Dir(strFilePath)
Do While Len(strFileName) > 0
'check to see if filename matches filter
If InStr(strFileName, strFileFilter) Then
If InStr(strFileName, "997") Then
FileOpen(1, strFilePath & strFileName, OpenMode.Input)
Do Until EOF(1)
strExclude = InputString(1, LOF(1))
Loop
pos = InStr(UCase(strExclude), "MANIFEST")
posinc = posinc + pos
pos = InStr(UCase(strExclude), "INVOICE")
posinc = posinc + pos
FileClose(1)
Else : posinc = 1
End If
If posinc > 0 Then
'add file to array
ReDim Preserve strFiles(i)
strFiles(i) = strFileName
i += 1
Else
My.Computer.FileSystem.MoveFile("l:\" & strFileName, "k:\" & strFileName)
End If
'MsgBox(strFileName & " " & IO.File.GetLastWriteTime(strFileName).ToString)
pos = 0
posinc = 0
End If
'get the next file
strFileName = Dir()
Loop
Return strFiles
End Function
Brief overview of the code above. An automated program fills the "L:\" directory with text files, and this program needs to print out certain files with "997" in the filename (namely files with "997" in the filename and containing the text "INVOICE" or "MANIFEST"). The ListFiles function does exactly this, then back in the Form1_Load() sub it is supposed to print each file, copy it, and delete the original.
Something to note, this code is developed in Visual Studio 2013 on Windows 7. The machine that actually runs this program is still on Windows XP.
I can see a few issues. the first and most obvious is the error handling:
You have a Try.. Catch with no error handling. You may be running in to an error without knowing it!! Add some output here, so you know if that is the case.
The second issue is to do with the way you are handling Process classes.
Instead of just calling System.Diagnostics.Process.Start in a loop and sleeping you should use the inbuilt method of handling execution. You are also not disposing of anything, which makes me die a little inside.
Try something like
Using p As New System.Diagnostics.Process
p.Start("Notepad.exe", " /p l:\" & f(i))
p.WaitForExit()
End Using
With both of these changes in place you should not have any issues. If you do there should at least be errors for you to look at and provide here, if necessary.

Open, Launch or Show a file for the user to read or write in vb.net

It sounds very simple but I have searched and cannot seem to find a way to open a log file which the user just created from my windows form app. The file exits I just want to open it after it is created.
I have a Dim path As String = TextBox1.Text and once the user names and clicks ok on the savefiledialog I have a msgbox that says "Done" and when you hit OK I have tried this
FileOpen(FreeFile, path, OpenMode.Input) but nothing happens. I just want it to open the log and show it to the user so they can edit or save it again or anything.
This is where I got the above code.
http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.filesystem.fileopen.aspx
Searching is difficult because everyone is trying to "Open" a file and process it during runtime. I am just trying to Show a file by Launching it like someone just double clicked it.
Here is the entire Export Button click Sub. It basically writes listbox items to file.
Private Sub btnExport_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExport.Click
Dim sfd As New SaveFileDialog
Dim path As String = TextBox1.Text
Dim arypath() As String = Split(TextBox1.Text, "\")
Dim pathDate As String
Dim foldername As String
foldername = arypath(arypath.Length - 1)
pathDate = Now.ToString("yyyy-MM-dd") & "_" & Now.ToString("hh;mm")
sfd.FileName = "FileScannerResults " & Chr(39) & foldername & Chr(39) & " " & pathDate
sfd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
sfd.Filter = "Text files (*.txt)|*.txt|CSV Files (*.csv)|*.csv"
sfd.ShowDialog()
path = sfd.FileName
Using SW As New IO.StreamWriter(path)
If CkbxFolder.Checked = True Then
SW.WriteLine("Folders")
For Each itm As String In ListBox1.Items
SW.WriteLine(itm)
Next
End If
If CkbxFiles.Checked = True Then
SW.WriteLine("Files")
For Each itm As String In ListBox2.Items
SW.WriteLine(itm)
Next
End If
End Using
MsgBox("Done...")
FileOpen(FreeFile, path, OpenMode.Input) 'Why can't I open a file for you...
End Sub
Do not use the old VB6 methods. They are still here for compatibility reason, the new code should use the more powerful methods in the System.IO namespace.
However, as said in comments, FileOpen don't show anything for you, just opens the file
You coud write
Using sr = new StreamReader(path)
Dim line = sr.ReadLine()
if !string.IsNullOrEmpty(line) Then
textBoxForLog.AppendText(line)
End If
End Using
or simply (if the file is not too big)
Dim myLogText = File.ReadAllText(path)
textBoxForLog.Text = myLogText
As alternative, you could ask the operating system to run the program associated with the file extension and show the file for you
Process.Start(path)
To get the same behavior as if the user double-clicked it, just use System.Diagnostics.Process, and pass the filename to it's Start method:
Process.Start(path)
This will open the file using whatever the default application is for that filename based on its extension, just like Explorer does when you double-click it.

Strange "IOException was unhandled"

(VB.NET, .NET 3.5)
I wrote the following function to read some text from txt file. It was working fine but now it's not. It keeps giving me this error message
"IOException was unhandled" and
" The process cannot access the file 'F:\kh_matt\ch1.txt' because it is being used by another process."
The ch1.txt is not even opened or being used by any program at all. I tried to move ch1.txt to another location (Drive D) still I got the same message error but just different location it says The process cannot access the file 'D:\ch1.txt' because it is being used by another process."
Here's my code block :
Private Sub btnRead_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRead.Click
Dim reader As StreamReader
Dim filelocation As String
filelocation = "F:\kh_matt\ch1.txt"
Dim chid As Integer
chid = 1
If System.IO.File.Exists(filelocation) = True Then
reader = New StreamReader(New FileStream(filelocation, FileMode.Open))
Else
MsgBox(filelocation, MsgBoxStyle.OkOnly)
End If
Dim MyStream As New StreamReader(Path.Combine(Application.StartupPath, filelocation))
Dim vArray() As String = MyStream.ReadToEnd.Split(CChar("$"))
MyStream.Close()
Dim count As Integer
For d As Integer = 0 To vArray.Length - 1 Step 1
If d = vArray.Length - 1 Then
Exit For
End If
InsertKh(chid, d + 1, vArray(d))
count = d + 1
Next
MsgBox("Done Inserting")
End Sub
It always points to this code :
Dim MyStream As New StreamReader(Path.Combine(Application.StartupPath, filelocation))
Where I debug and press the respective button. Can anyone point out what the problem is ? Thanks
I think this is your problem:
If System.IO.File.Exists(filelocation) = True Then
reader = New StreamReader(New FileStream(filelocation, FileMode.Open))
If the file exists it will open a StreamReader on it, then try and open another StreamReader on the same file, which will lock the file, causing this line:
Dim MyStream As New StreamReader(Path.Combine(Application.StartupPath, filelocation))
to fail.
Also, some pointers:
consider using the System.IO.File.ReadAllText() method instead, much easier
if you must use streams, wrap them in a using block to ensure they're freed correctly, for example:
`
Dim vArray() As String
using (Dim MyStream As New StreamReader(Path.Combine(Application.StartupPath, filelocation))
{
vArray = MyStream.ReadToEnd.Split(CChar("$"))
}
(sorry if the above code isn't 100% correct, I don't write much VB.Net)
It seems you open the file twice, which is probably what's causing your error:
reader = New StreamReader(New FileStream(filelocation, FileMode.Open))
...
Dim MyStream As New StreamReader(Path.Combine(Application.StartupPath, filelocation))
Are you sure that's what you intend to do? It looks like you can remove MyStream and use reader instead. Also, you don't have to use Path.Combine, since filelocation is not relative.
Make sure that you close your stream & streamreader once you've finished reading the file, even when an exception is being thrown.
Use a try/finally block, and close the stream / streamreader in the finally block.
Thanks all for the reply. It's my mistake. I forgot to comment out my code that I wrote for testing earlier. After commenting this code out it works like before.
'If System.IO.File.Exists(filelocation) = True Then
' reader = New StreamReader(New FileStream(filelocation, FileMode.Open))
'Else
' MsgBox(filelocation, MsgBoxStyle.OkOnly)
'End If
Have a good day.

How do I delay a vb.net program until a file operation completes?

I have this:
Dim myTemp As String
myTemp = System.DateTime.Now().ToString("MMMddyyyy_HHmmss") & ".pdf"
System.IO.File.Copy(myFile, "c:\" & myTemp)
Application.DoEvents()
OpenFile(myTemp)
The problem is that when I call OpenFile, which is just a call to a sub that opens a file, it cannot find the file. This is because it is calling it so quickly that the program doesn't have time to actually create the file before the open takes place.
I thought that DoEvents() would rectify this but it does not. I need to wait until the file is created before I open the file. How can I do that?
I don't really know much VB.NET, but isn't Copy a blocking call? Are you sure you're not just trying to open the file from the wrong location (or the unescaped backslash invalidates the path)?
What about this? I've added the drive letter to OpenFile, and escaped the backslash both places.
Dim myTemp As String
myTemp = System.DateTime.Now().ToString("MMMddyyyy_HHmmss") & ".pdf"
System.IO.File.Copy(myFile, "c:\\" & myTemp)
OpenFile("c:\\" & myTemp)
Ideally you should perform the copy on a separate thread that informs the main GUI thread when it is done so it can then perform the open through an Invoke call.
Use FileSystemWatcher to alert you when the file is created. No loops.
https://web.archive.org/web/1/http://articles.techrepublic%2ecom%2ecom/5100-10878_11-6165137.html
This is ugly but it works for me
Function WaitForFile(fullPath, wdelay)
Dim vd_start As Date
vd_start = Now()
Dim vd_end As Date
Dim wsec, wmin, whour, wt5string As Integer
Dim wtstring As String
Dim count As Integer
Dim wscale As Integer
Dim vd_1 As Date
Dim Vo_fileinfo As FileInfo
Dim fs As FileStream
wsec = Format(wdelay Mod 60, "00")
wmin = Format(Int(wdelay / 60), "00")
whour = Format(Int(wdelay / (60 * 60)), "00")
wtstring = CStr(whour) + ":" + CStr(wmin) + ":" + CStr(wsec)
Dim duration = New System.TimeSpan(0, whour, wmin, wsec)
vd_end = vd_start.Add(duration)
On Error GoTo error1
Dim vsize1, vsize2 As Long
While vd_start < vd_end
fs = New FileStream(fullPath, FileMode.Open)
fs.ReadByte()
fs.Seek(0, SeekOrigin.Begin)
fs.Close()
Vo_fileinfo = New FileInfo(fullPath)
vsize1 = Vo_fileinfo.Length
Threading.Thread.Sleep(500)
Vo_fileinfo = New FileInfo(fullPath)
vsize2 = Vo_fileinfo.Length
If vsize1 <> vsize2 Then GoTo error1
GoTo finalgoto
error1:
Err.Clear()
vd_start = Now()
End While
WaitForFile = False
GoTo Endgoto
finalgoto: WaitForFile = True
Endgoto:
End Function
This is a bit hacky, but it should work.
Do Until (System.IO.File.Exists("C:\" & myTemp))
Threading.Thread.Sleep(1)
Loop
That isn't really what Doevents is used for. It is most frequently used to let the UI message queue clear out (let the UI have some CPU time to refresh). It is slightly more complex than I am describing, but that isn't the point of your question so I will move on.
Try this to make the critical section of your code block:
SyncLock Me
System.IO.File.Copy(myFile, "c:\" & myTemp)
Application.DoEvents()
End SyncLock
OpenFile(myTemp)
In addition to Tom's answer, isnt it better to put a Application.DoEvents() rather then making the thread sleep?
First, you should not call DoEvents anywhere. For the most part, when it is used, it is a hack to circumvent what should really be an asynchronous operation.
That being said, the Copy method is a synchronous operation. The call to OpenFile will not occur until the call to Copy completes.
That being said when the call to OpenFile occurs, if the file does not exist, it is because you copied it to the wrong place, or because some other process is working on the file in question.
I thinf Synclock is not good for this case
for explaination, MSDN can help me
The SyncLock statement ensures that multiple threads do not execute the same statements at the same time. When the thread reaches the SyncLock block, it evaluates the expression and maintains this exclusivity until it has a lock on the object that is returned by the expression. This prevents an expression from changing values during the running of several threads, which can give unexpected results from your code.
in my opinion, copy is blocking method, so thread waits until copying is done
can`t be problem in another place?
dim SourceFile as string
dim DestinationFile as string
SourceFile = "c:/archivo.txt"
DestinationFile = "c:/destino/archivo.txt"
If System.IO.File.Exists(SourceFile) = True Then
System.IO.File.Copy(SourceFile, DestinationFile, True)
'or
'My.Computer.FileSystem.CopyFile(SourceFile, DestinationFile, FileIO.UIOption.AllDialogs, FileIO.UICancelOption.DoNothing)
SourceFile = ""
DestinationFile = ""
else
MessageBox.Show("the file don't copy!")
end if
System.Threading.Thread.Sleep(1000);