What is the proper way to stop the whole operation of the FileStream when copying multiple files. When i call the Stop Download() function, it stops, but when i start the copy again it doesn't start like the way it was. What should i do?
code:
Private dStop As Boolean = False
Dim streamRead As FileStream
Dim streamWrite As FileStream
Public Function StopDownload()
dStop = True
streamWrite.Flush()
streamWrite.Close()
streamRead.Close()
End Function
Public Sub Copier(ByVal URL As String, ByVal Location As String) As Boolean
streamRead = New FileStream(URL, System.IO.FileMode.Open)
streamWrite = New FileStream(Location, System.IO.FileMode.Create)
Dim lngLen As Long = streamRead.Length - 1
Dim byteBuffer(1048576) As Byte
Dim intBytesRead As Integer
While streamRead.Position < lngLen And dStop = False 'This is where i stop the process of copying
intBytesRead = (streamRead.Read(byteBuffer, 0, 1048576))
streamWrite.Write(byteBuffer, 0, intBytesRead)
Pbar1.value = CInt(streamRead.Position / lngLen * 100)
Application.DoEvents() 'do it
End While
streamWrite.Flush()
streamWrite.Close()
streamRead.Close()
End Sub
I just have to put this at the beginning my Copier Public Sub.
dstop = False
for it to start a new copying process.
Related
I have this code that starts some threads by iterating through a list of strings and send each one to a Sub which connects to a webservice and waits for a result:
Public Shared Function StartThreading(names As String())
Dim threads As List(Of Thread) = New List(Of Thread)()
For Each name In names
Dim t As Thread = New Thread(New ParameterizedThreadStart(Sub() CallWebService(name)))
threads.Add(t)
Next
For i As Integer = 0 To threads.Count - 1
Dim t = threads(i)
Dim name = names(i)
t.Start(name)
Next
For Each t As Thread In threads
t.Join()
Next
End Function
The Sub for the webservice caller is:
Public Shared Sub CallWebService(inputxml As String)
Dim _url = "http://10.231.58.173:8080/ps/services/ProcessServer?WSDL"
Dim _action = "http://10.231.58.173:8080/ps/services/ProcessServer"
Dim soapEnvelopeXml As XmlDocument = CreateSoapEnvelope(inputxml)
Dim webRequest As HttpWebRequest = CreateWebRequest(_url, _action)
Dim appPath As String = System.AppDomain.CurrentDomain.BaseDirectory
Dim configpath As String = appPath + "\Config.ini"
Dim configdata As IniData = Functii.ReadIniFile(configpath)
Dim outputxmlsave = configdata("PATHS")("OUTPUTXML")
InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest)
Dim asyncResult As IAsyncResult = webRequest.BeginGetResponse(Nothing, Nothing)
asyncResult.AsyncWaitHandle.WaitOne()
Dim soapResult As String
Using webResponse As WebResponse = webRequest.EndGetResponse(asyncResult)
Using rd As StreamReader = New StreamReader(webResponse.GetResponseStream())
soapResult = rd.ReadToEnd()
End Using
File.WriteAllText(outputxmlsave & "\" & "test.xml", soapResult.ToString)
Console.Write(soapResult)
End Using
End Sub
How can I know that all threads are done successfully or not? Is there something I can use to return a True value if they are all done?
I am trying to download multiple directories from FTP server to my local machine,
I have tried this,
Const localFile As String = "C:\Documents and Settings\cr\Desktop\T\New Folder\"
Const remoteFile As String = "textbox.Text"
Const host As String = "ftp://ftp.example.com"
Const username As String = "username"
Const password As String = "password"
For i1 = 0 To ListBox1.SelectedItems.Count - 1
Dim li As New ListViewItem
li = ListView1.Items.Add(ListBox1.SelectedItems(i1))
Dim URI1 As String = host + remoteFile & "/" & ListBox1.SelectedItems(i1)
Dim ftp1 As System.Net.FtpWebRequest = CType(FtpWebRequest.Create(URI1), FtpWebRequest)
ftp1.Credentials = New System.Net.NetworkCredential(username, password)
ftp1.KeepAlive = False
ftp1.UseBinary = True
ftp1.Method = System.Net.WebRequestMethods.Ftp.DownloadFile
Using response As System.Net.FtpWebResponse = CType(ftp1.GetResponse, System.Net.FtpWebResponse)
Using responseStream As IO.Stream = response.GetResponseStream
Dim length As Integer = response.ContentLength
Dim bytes(length) As Byte
'loop to read & write to file
Using fs As New IO.FileStream(localFile & ListBox1.SelectedItems(i1), IO.FileMode.Create)
Dim buffer(2047) As Byte
Dim read As Integer = 1
Do
read = responseStream.Read(buffer, 0, buffer.Length)
fs.Write(buffer, 0, read)
Loop Until read = 0 'see Note(1)
responseStream.Close()
fs.Flush()
fs.Close()
End Using
responseStream.Close()
End Using
response.Close()
End Using
li.BackColor = Color.Aquamarine
Next
But here the problem is that I am able to download multiple files from folders, but unable to download the sub directories and their contents from the main directory.
Basically the main directory consist of files and sub directories both. So is there any possible way to download sub directory and its contents from FTP?
Thanks in advance.
Translating my answer to C# Download all files and subdirectories through FTP to VB.NET:
The FtpWebRequest does not have any explicit support for recursive file download (or any other recursive operation). You have to implement the recursion yourself:
List the remote directory
Iterate the entries, downloading files and recursing into subdirectories (listing them again, etc.)
A tricky part is to identify files from subdirectories. There's no way to do that in a portable way with the FtpWebRequest. The FtpWebRequest unfortunately does not support the MLSD command, which is the only portable way to retrieve directory listing with file attributes in FTP protocol. See also Checking if object on FTP server is file or directory.
Your options are:
Do an operation on a file name that is certain to fail for file and succeeds for directories (or vice versa). I.e. you can try to download the "name". If that succeeds, it's a file, if that fails, it's a directory.
You may be lucky and in your specific case, you can tell a file from a directory by a file name (i.e. all your files have an extension, while subdirectories do not)
You use a long directory listing (LIST command = ListDirectoryDetails method) and try to parse a server-specific listing. Many FTP servers use *nix-style listing, where you identify a directory by the d at the very beginning of the entry. But many servers use a different format. The following example uses this approach (assuming the *nix format)
Sub DownloadFtpDirectory(
url As String, credentials As NetworkCredential, localPath As String)
Dim listRequest As FtpWebRequest = WebRequest.Create(url)
listRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails
listRequest.Credentials = credentials
Dim lines As List(Of String) = New List(Of String)
Using listResponse As FtpWebResponse = listRequest.GetResponse(),
listStream As Stream = listResponse.GetResponseStream(),
listReader As StreamReader = New StreamReader(listStream)
While Not listReader.EndOfStream
lines.Add(listReader.ReadLine())
End While
End Using
For Each line As String In lines
Dim tokens As String() =
line.Split(New Char() {" "}, 9, StringSplitOptions.RemoveEmptyEntries)
Dim name As String = tokens(8)
Dim permissions As String = tokens(0)
Dim localFilePath As String = Path.Combine(localPath, name)
Dim fileUrl As String = url + name
If permissions(0) = "d" Then
If Not Directory.Exists(localFilePath) Then
Directory.CreateDirectory(localFilePath)
End If
DownloadFtpDirectory(fileUrl + "/", credentials, localFilePath)
Else
Dim downloadRequest As FtpWebRequest = WebRequest.Create(fileUrl)
downloadRequest.Method = WebRequestMethods.Ftp.DownloadFile
downloadRequest.Credentials = credentials
Using downloadResponse As FtpWebResponse = downloadRequest.GetResponse(),
sourceStream As Stream = downloadResponse.GetResponseStream(),
targetStream As Stream = File.Create(localFilePath)
Dim buffer As Byte() = New Byte(10240 - 1) {}
Dim read As Integer
Do
read = sourceStream.Read(buffer, 0, buffer.Length)
If read > 0 Then
targetStream.Write(buffer, 0, read)
End If
Loop While read > 0
End Using
End If
Next
End Sub
Use the function like:
Dim credentials As NetworkCredential = New NetworkCredential("user", "mypassword")
Dim url As String = "ftp://ftp.example.com/directory/to/download/"
DownloadFtpDirectory(url, credentials, "C:\target\directory")
If you want to avoid troubles with parsing the server-specific directory listing formats, use a 3rd party library that supports the MLSD command and/or parsing various LIST listing formats; and recursive downloads.
For example with WinSCP .NET assembly you can download whole directory with a single call to the Session.GetFiles:
' Setup session options
Dim SessionOptions As SessionOptions = New SessionOptions
With SessionOptions
.Protocol = Protocol.Ftp
.HostName = "ftp.example.com"
.UserName = "user"
.Password = "mypassword"
End With
Using session As Session = New Session()
' Connect
session.Open(SessionOptions)
' Download files
session.GetFiles("/directory/to/download/*", "C:\target\directory\*").Check()
End Using
Internally, WinSCP uses the MLSD command, if supported by the server. If not, it uses the LIST command and supports dozens of different listing formats.
The Session.GetFiles method is recursive by default.
(I'm the author of WinSCP)
Check out my FTP class: Its pretty straight forward.
Take a look at my FTP class, it might be exactly what you need.
Public Class FTP
'-------------------------[BroCode]--------------------------
'----------------------------FTP-----------------------------
Private _credentials As System.Net.NetworkCredential
Sub New(ByVal _FTPUser As String, ByVal _FTPPass As String)
setCredentials(_FTPUser, _FTPPass)
End Sub
Public Sub UploadFile(ByVal _FileName As String, ByVal _UploadPath As String)
Dim _FileInfo As New System.IO.FileInfo(_FileName)
Dim _FtpWebRequest As System.Net.FtpWebRequest = CType(System.Net.FtpWebRequest.Create(New Uri(_UploadPath)), System.Net.FtpWebRequest)
_FtpWebRequest.Credentials = _credentials
_FtpWebRequest.KeepAlive = False
_FtpWebRequest.Timeout = 20000
_FtpWebRequest.Method = System.Net.WebRequestMethods.Ftp.UploadFile
_FtpWebRequest.UseBinary = True
_FtpWebRequest.ContentLength = _FileInfo.Length
Dim buffLength As Integer = 2048
Dim buff(buffLength - 1) As Byte
Dim _FileStream As System.IO.FileStream = _FileInfo.OpenRead()
Try
Dim _Stream As System.IO.Stream = _FtpWebRequest.GetRequestStream()
Dim contentLen As Integer = _FileStream.Read(buff, 0, buffLength)
Do While contentLen <> 0
_Stream.Write(buff, 0, contentLen)
contentLen = _FileStream.Read(buff, 0, buffLength)
Loop
_Stream.Close()
_Stream.Dispose()
_FileStream.Close()
_FileStream.Dispose()
Catch ex As Exception
MessageBox.Show(ex.Message, "Upload Error: ", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
Public Sub DownloadFile(ByVal _FileName As String, ByVal _ftpDownloadPath As String)
Try
Dim _request As System.Net.FtpWebRequest = System.Net.WebRequest.Create(_ftpDownloadPath)
_request.KeepAlive = False
_request.Method = System.Net.WebRequestMethods.Ftp.DownloadFile
_request.Credentials = _credentials
Dim _response As System.Net.FtpWebResponse = _request.GetResponse()
Dim responseStream As System.IO.Stream = _response.GetResponseStream()
Dim fs As New System.IO.FileStream(_FileName, System.IO.FileMode.Create)
responseStream.CopyTo(fs)
responseStream.Close()
_response.Close()
Catch ex As Exception
MessageBox.Show(ex.Message, "Download Error: ", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
Public Function GetDirectory(ByVal _ftpPath As String) As List(Of String)
Dim ret As New List(Of String)
Try
Dim _request As System.Net.FtpWebRequest = System.Net.WebRequest.Create(_ftpPath)
_request.KeepAlive = False
_request.Method = System.Net.WebRequestMethods.Ftp.ListDirectoryDetails
_request.Credentials = _credentials
Dim _response As System.Net.FtpWebResponse = _request.GetResponse()
Dim responseStream As System.IO.Stream = _response.GetResponseStream()
Dim _reader As System.IO.StreamReader = New System.IO.StreamReader(responseStream)
Dim FileData As String = _reader.ReadToEnd
Dim Lines() As String = FileData.Split(New String() {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries)
For Each l As String In Lines
ret.Add(l)
Next
_reader.Close()
_response.Close()
Catch ex As Exception
MessageBox.Show(ex.Message, "Directory Fetch Error: ", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
Return ret
End Function
Private Sub setCredentials(ByVal _FTPUser As String, ByVal _FTPPass As String)
_credentials = New System.Net.NetworkCredential(_FTPUser, _FTPPass)
End Sub
End Class
To initialize:
Dim ftp As New FORM.FTP("username", "password")
ftp.UploadFile("c:\file.jpeg", "ftp://domain/file.jpeg")
ftp.DownloadFile("c:\file.jpeg", "ftp://ftp://domain/file.jpeg")
Dim directory As List(Of String) = ftp.GetDirectory("ftp://ftp.domain.net/")
ListBox1.Items.Clear()
For Each item As String In directory
ListBox1.Items.Add(item)
Next
I want to check if my edited stream have my bytes but the result is always failed I just can't find the wrong with my function
Public Function passbyte(ByVal filename As String, ByVal pass As String)
As Boolean
Dim passarray(0 to 2) As Byte
Dim realarray(0 To 2) As Byte
Dim result = False
Dim pos As Integer
pos = 0
If IO.File.Exists(filename) Then
Using Stream As New FileStream(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)
Stream.Seek(pos, SeekOrigin.Begin)
passarray = System.Text.Encoding.ASCII.GetBytes(pass)
Stream.Write(passarray, 0, 3)
Stream.Read(realarray, 0, 3)
If realarray(0) = passarray(0) and realarray(1) = passarray(1) and realarray(2) = passarray(2) Then
result = True
MsgBox("Success")
Else
result = False
MsgBox("Failed")
End If
stream.close()
End Using
End If
Return result
End Function
Can't you do this without the loops?
If pass = My.Computer.FileSystem.ReadAllText(filename) Then
I have a little problem with an XML file and a Stream. I create and save an XML file in a Stream, encrypt the Stream and then save it to a normal file.
I want to read this XML, however I can only do this if I use a FileStream and write a decrypted file to disk.
Is there a way to decrypt and keep this file in memory?
This is my code:
XMLDecriptato = New MemoryStream()
Using stream_readerX As New StreamReader(XMLDecriptato, Text.Encoding.UTF8)
XMLDecriptato.SetLength(0)
Dim FStreamCrypted As FileStream = File.Open(varTitolo, FileMode.Open, FileAccess.Read)
FStreamCrypted.Seek(0, SeekOrigin.Begin)
CryptStream(Pass, FStreamCrypted, XMLDecriptato, Type.Decrypt)
'try to read the stream
Dim xDocumentX As New XmlDocument()
xDocumentX.Load(stream_readerX) 'here is the error
End Using
It keeps saying that the Stream is closed. I have tried also another way. The only one that works is to write the stream to the hard disk with a FileStream.
And that is the Encrypt/Decrypt Sub:
Public Sub CryptStream(ByVal Psw As String, ByVal IN_Stream As Stream, ByVal OUT_Stream As Stream, ByVal CrtType As CryptType)
Dim AES_Provider As New AesCryptoServiceProvider()
Dim Key_Size_Bits As Integer = 0
For i As Integer = 1024 To 1 Step -1
If (aes_provider.ValidKeySize(i)) Then
Key_Size_Bits = i
Exit For
End If
Next i
Dim Block_Size_Bits As Integer = AES_Provider.BlockSize
Dim Key() As Byte = Nothing
Dim IV() As Byte = Nothing
Dim Salt() As Byte = "//my salt//"
MakeKeyAndIV(Psw, Salt, Key_Size_Bits, Block_Size_Bits, Key, IV)
Dim Crypto_Transform As ICryptoTransform = Nothing
Select Case CrtType
Case CryptType.Encrypt
Crypto_Transform = AES_Provider.CreateEncryptor(key, iv)
Case CryptType.Decrypt
Crypto_Transform = AES_Provider.CreateDecryptor(key, iv)
End Select
If Crypto_Transform Is Nothing Then Exit Sub
Try
Using Crypto_Stream As New CryptoStream(OUT_Stream, Crypto_Transform, CryptoStreamMode.Write)
Const Block_Size As Integer = 1024
Dim Buffer(Block_Size) As Byte
Dim Bytes_Read As Integer
Do
Bytes_Read = IN_Stream.Read(Buffer, 0, Block_Size)
If (Bytes_Read = 0) Then Exit Do
Crypto_Stream.Write(Buffer, 0, Bytes_Read)
Loop
End Using
Catch ex As Exception
End Try
Crypto_Transform.Dispose()
End Sub
It turns out that when CryptoStream.Dispose() is called by the Using/End Using block, the CryptoStream also disposes the underlying stream (in this case your MemoryStream). This behaviour can be confirmed by checking Microsoft's Reference Source.
Since the CryptoStream doesn't have a LeaveOpen flag like the StreamReader does since .NET 4.5 and up, I removed the Using block and wrote the necessary calls on my own for your method.
The changes:
Public Sub CryptStream(ByVal Psw As String, ByVal IN_Stream As Stream, ByVal OUT_Stream As Stream, ByVal CrtType As CryptType, Optional ByVal LeaveOpen As Boolean = False)
...code...
Try
Dim Crypto_Stream As New CryptoStream(OUT_Stream, Crypto_Transform, CryptoStreamMode.Write)
Const Block_Size As Integer = 1024
Dim Buffer(Block_Size) As Byte
Dim Bytes_Read As Integer
Do
Bytes_Read = IN_Stream.Read(Buffer, 0, Block_Size)
If (Bytes_Read = 0) Then Exit Do
Crypto_Stream.Write(Buffer, 0, Bytes_Read)
Loop
If Crypto_Stream.HasFlushedFinalBlock = False Then Crypto_Stream.FlushFinalBlock()
If LeaveOpen = False Then
Crypto_Stream.Dispose()
End If
Catch ex As Exception
End Try
...code...
End Sub
And since data will be fed into the MemoryStream its position will have changed, so you have to reset that too before loading the XML document:
XMLDecriptato = New MemoryStream()
Using stream_readerX As New StreamReader(XMLDecriptato, System.Text.Encoding.UTF8)
Dim FStreamCrypted As FileStream = File.Open(OpenFileDialog1.FileName, FileMode.Open, FileAccess.Read)
CryptStream(Pass, FStreamCrypted, XMLDecriptato, CryptType.Decrypt, True) 'True = Leave the underlying stream open.
XMLDecriptato.Seek(0, SeekOrigin.Begin) 'Reset the MemoryStream's position.
Dim xDocumentX As New XmlDocument()
xDocumentX.Load(stream_readerX)
End Using
As you might have noticed I removed the FStreamCrypted.Seek(0, SeekOrigin.Begin) line. This was because you've just opened the stream and done nothing with it, so the position will already be at 0.
Hope this helps!
This is such a great place to ask questions!
I'm facing one problem.
I'm trying to send an image from an AutoIT client over to a server that is written in VB.NET
Here is the code for the AutoIT Client:
TCPStartup()
$MainSocket = TCPConnect("127.0.0.1", 9832)
$PATH = _ScreenCapture_Capture("")
$Data2Send = "RemoteDESK|" & _Base64Encode(HBITMAP_To_Bytes($PATH)) & "<EOF>"
TCPSend($MainSocket, $Data2Send)
And here is the code for the VB.NET server:
Data handler:
Private Sub GotInfo(ByVal Data As String, ByVal Sender As Socket)
Dim Cut() As String = Data.Split("|")
Select Case Cut(0)
Case "RemoteDESK"
Dim ImgString As String = Cut(1)
PictureBox1.Image = B64ToImage(ImgString)
End Select
End Sub
Base 64 String to Image Fucntion:
Private Function B64ToImage(ByVal B64 As String) As Image
Dim ByAr() As Byte = Convert.FromBase64String(B64) 'Exception Happens here
Dim img As Image
Dim MS As New MemoryStream(ByAr)
Try
img = Image.FromStream(MS)
Catch ex As Exception
Return Nothing
End Try
Return img
End Function
The OnReceive Sub:
Private Sub OnReceive(ByVal ar As IAsyncResult)
Dim Content As String = String.Empty
Dim State As StateObject = DirectCast(ar.AsyncState, StateObject)
Dim Handler As Socket = State._MySocket
Try
Dim BytesRead As Integer = Handler.EndReceive(ar)
If BytesRead > 0 Then
State._SB.Append(Encoding.ASCII.GetString(State.Data))
Content = State._SB.ToString
If Content.IndexOf("<EOF>") > -1 Then
Dim ReadContent As String = Content.Remove(Content.IndexOf("<EOF>"))
RaiseEvent GotInfo(ReadContent, State._MySocket)
Else
Handler.BeginReceive(State.Data, 0, State.BufferSize, SocketFlags.None, New AsyncCallback(AddressOf OnReceive), State)
End If
End If
Catch ex As Exception
RaiseEvent ClientDC(Handler)
End Try
End Sub
Alright, so now I used a text comparing tool, and every time on line 53, the received string has changed, as in the the 2 lines of text are on the same line compared to the autoit's output.
The autoit output is the readable one.