Check for file/subdirectory existence with VB.NET using FtpWebRequest - vb.net

I have a problem with my FTP upload and I hope you can help me. I'm trying create folders and then upload files to them. What my program should do is checking if a folder already exists, and if not, create a new one with the name checked before. The program runs fine, except for the error described below.
My Problem:
I want to upload a folder called ghandle -> works as intended.
After that, I want to upload a folder called handle -> doesn't work, because the .Contains method that checks the folders on the FTP server, finds ghandle and stops, because ghandle contains handle.
Are there other options like .Contains which will just check for whole words or exact matches?
Here is my source code:
Dim dirname = Path.GetFileNameWithoutExtension(openFileDialogHtml.FileName) & "_files"
Dim ftp = "ftp://" & ftp_address.Text & "/"
Dim user = ftp_user.Text
Dim pass = ftp_password.Text
Dim request As Net.FtpWebRequest = Net.FtpWebRequest.Create(ftp)
Dim creds As Net.NetworkCredential = New Net.NetworkCredential(user, pass)
request.Credentials = creds
Dim resp As Net.FtpWebResponse = Nothing
request.Method = Net.WebRequestMethods.Ftp.ListDirectoryDetails
request.KeepAlive = True
Using resp
resp = request.GetResponse()
Dim sr As StreamReader = New StreamReader(resp.GetResponseStream(), System.Text.Encoding.ASCII)
Dim s As String = sr.ReadToEnd()
If Not s.Contains(dirname) Then
request = Net.FtpWebRequest.Create(ftp & dirname)
request.Credentials = creds
request.Method = Net.WebRequestMethods.Ftp.MakeDirectory
resp = request.GetResponse()
MsgBox("Created folder " & dirname)
Else
MsgBox("Folder " & dirname & " already exists!")
End If
End Using
Thanks in advance

First, use ListDirectory, not ListDirectoryDetails. The ListDirectory returns plain names only, what is enough for your purpose and easy to parse.
Then just split the output to an array of individual file names, using the String.Split method:
Dim names As String() =
sr.ReadToEnd().Split(
New Char() {vbCr, vbLf}, StringSplitOptions.RemoveEmptyEntries)
And use the IEnumerable.Contains extension method to check for given file name:
If Not names.Contains(dirname) Then

Related

VB.NET to download latest file name with timestamp in its name from FTP server

I want to pull a file from my FTP server into my local drive. However the most difficult part of do this is that the file name is a timestamp that changes on a daily basis. The program should download the file regardless of how it has changed with the date; year, month, hour, minutes, and seconds. The format of the name are always the same. File name example is below in bold. Please advise!
For example,
username - meUser
password - mepswrd
and the URL to the FTP
/afea/euser/aefe/aole/efa/
and the path I want the file to save after download it.
C:\Users\alae\Desktop\loaef
and the file is in FORMAT
20160223.171234.BA_DESRP_20160121.txt
The only part to the file that doesn't change is BA_DESRP, all the other part can change as it is a timestamp.
This is my code to start with:
Const lf As String = "C:\Users\alae\Desktop\loaef"
Const rf As String = "/afea/euser/aefe/aole/efa/"
Const ht As String = "host"
Const un As String = "username"
Const pw As String = "password"
Dim URI As String = ht & rf
Dim ftp As System.Net.FtpWebRequest = _
CType(FtpWebRequest.Create(URI), FtpWebRequest)
ftp.Credentials = New _
System.Net.NetworkCredential(un, pw)
There's no easy way with the FtpWebRequest (or any other functionality readily available in the .NET framework). You have to:
List the remote directory using the WebRequestMethods.Ftp.ListDirectory
Filter the returned list to those containing the BA_DESRP
Select the latest out of those
And download it
Dim url As String = "ftp://ftp.example.com/remote/path/"
Dim credentials As NetworkCredential = New NetworkCredential("username", "password")
Const localPath = "C:\local\path"
Dim listRequest As FtpWebRequest = WebRequest.Create(url)
listRequest.Method = WebRequestMethods.Ftp.ListDirectory
listRequest.Credentials = credentials
Dim latest As String = Nothing
Using listResponse As FtpWebResponse = listRequest.GetResponse(),
listStream As Stream = listResponse.GetResponseStream(),
listReader As StreamReader = New StreamReader(listStream)
While Not listReader.EndOfStream
Dim filename As String = listReader.ReadLine()
If filename.Contains("BA_DESRP") Then
Console.WriteLine("Found {0} ...", filename)
If (latest Is Nothing) OrElse (latest < filename) Then
latest = filename
End If
End If
End While
End Using
If Not latest Is Nothing Then
Console.WriteLine("Downloading {0} ...", latest)
Dim webClient As New WebClient()
webClient.Credentials = credentials
webClient.DownloadFile(url + latest, Path.Combine(localPath, latest))
End If
Or use another FTP library with more powerful functionality.
For example with WinSCP .NET assembly:
Const localPath = "C:\local\path\"
Const remotePath = "/remote/path"
Dim sessionOptions As New SessionOptions
With sessionOptions
.Protocol = Protocol.Ftp
.HostName = "ftp.example"
.UserName = "username"
.Password = "password"
End With
Using session As New Session
session.Open(sessionOptions)
Dim latest As RemoteFileInfo =
session.ListDirectory(remotePath).Files.
Where(Function(file) file.Name.Contains("BA_DESRP")).
OrderByDescending(Function(file) file.Name).
FirstOrDefault()
If Not latest Is Nothing Then
Console.WriteLine("Downloading {0} ...", latest)
session.GetFiles(latest.FullName, localPath).Check()
End If
End Using
If you can use the actual file timestamp (not the timestamp in its name), it would be even more straightforward. See Downloading the most recent file.
(I'm the author of WinSCP)
This will get you the list of files in the directory. Since your file name already includes the timestamp, you just need to parse it out from the file name, and then ultimately store each timestamp in a variable where you can then compare the next file's time stamp to. if next file is greater than the value you in your variable, assign that value. finally when you are done, your var should reflect the file name you need and at that stage you can call the download method to get the file.
Dim request As FtpWebRequest = WebRequest.Create("ftp://" & "servername" & "/" & "directory" & "/*")
request.Method = WebRequestMethods.Ftp.ListDirectory
request.Credentials = New NetworkCredential("username", "password")
Using reader As New StreamReader(request.GetResponse().GetResponseStream())
Do Until reader.EndOfStream
Console.WriteLine(reader.ReadLine())
Loop
End Using
since you say thousands for files, this route may not be the best option for you. if you are not restricted to .NET, you may want to explore alternative options, such as using a ftp client where you may be able to search by the actual time stamp on files...

Delete FTP files with name containing a string (matching mask)

I would like to delete all files on an FTP server, whose names contain a certain string.
For example I have these files on the FTP:
pippo_1.jpg
pippo_2.jpg
pippo_3.jpg
pluto_1.jpg
I would like delete all file that contain pippo.
How can I delete all these files with a single operation?
Thank you!
No implementation of the FTP protocol in .NET framework allows this in a single operation.
You have to list the remote directory, filter the files you want to delete and delete them one by one.
If you really want to do this in a single operation, you have use a 3rd party library, that supports operations with file masks. For example WinSCP .NET assembly allows this with its Session.RemoveFiles method:
Dim sessionOptions As New SessionOptions
With sessionOptions
.Protocol = Protocol.Ftp
.HostName = "ftp.example.com"
.UserName = "username"
.Password = "password"
End With
Using session As New Session
session.Open(sessionOptions)
session.RemoveFiles("/remote/path/pippo*").Check()
End Using
(I'm the author of WinSCP)
If you do not want to use a 3rd party library, do as suggested above:
Dim url As String = "ftp://ftp.example.com/remote/path/"
Dim credentials As NetworkCredential = New NetworkCredential("username", "password")
Dim listRequest As FtpWebRequest = WebRequest.Create(url)
listRequest.Method = WebRequestMethods.Ftp.ListDirectory
listRequest.Credentials = credentials
Using listResponse As FtpWebResponse = listRequest.GetResponse(),
listStream As Stream = listResponse.GetResponseStream(),
listReader As StreamReader = New StreamReader(listStream)
While Not listReader.EndOfStream
Dim filename As String = listReader.ReadLine()
If filename.StartsWith("pippo") Then
Dim deleteRequest As FtpWebRequest = WebRequest.Create(url + filename)
deleteRequest.Method = WebRequestMethods.Ftp.DeleteFile
deleteRequest.Credentials = credentials
deleteRequest.GetResponse()
End If
End While
End Using

FTP Plain Text File To Specific Directory

I am taking over a process that is completely done by hand and trying to automate it. One step is to FTP a plain text file to a specific directory on an FTP server. Everything I see when I search is dropping the file on the server not putting it in a specific directory. The error I get is file name not allowed, except it is the same name that is manually FTP'ed. Below is what code I have. What am I missing?
LocalFile = Path.GetFileName(TheFile)
URI = TheHost & RemoteDir & LocalFile
TheFtpClient = CType(FtpWebRequest.Create(URI), FtpWebRequest)
TheFtpClient.Credentials = New NetworkCredential(UserName, PassWord)
TheFtpClient.KeepAlive = False
TheFtpClient.Method = WebRequestMethods.Ftp.UploadFile
FileReader = New StreamReader(TheFile)
FileContents = Encoding.UTF8.GetBytes(FileReader.ReadToEnd())
FileReader.Close()
TheFtpClient.ContentLength = FileContents.Length
RequestStream = TheFtpClient.GetRequestStream()
RequestStream.Write(FileContents, 0, FileContents.Length)
RequestStream.Close()
TheResponse = CType(TheFtpClient.GetResponse(), FtpWebResponse)
Console.WriteLine("[" & TheResponse.StatusDescription & "]")

vb.net FTP - works in some cases

i currently have this code as my FTP code (Which works a charm!)
Using ms As New System.IO.MemoryStream
test.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Png)
Using wc As New System.Net.WebClient
wc.UploadData("ftp://" & My.Settings.username & ":" & My.Settings.password & "#ftp." & My.Settings.server & My.Settings.imagelocation & filename & ".jpg", ms.ToArray())
End Using
End Using
however i have a new username and directory etc, and they contain "#" this is my username for example: "snap#example.com"
but my username before would be for instance "test" you see without the "#" im guessing its because it messes with the "#ftp" part, Any suggestions how to fix?
Short answer:
Encode your username and password using System.Web.HttpUtility.UrlPathEncode before creating your URL.
Long answer:
According to the IETF's RFC 1738, which is a standards track document about URLs, it explicitly says
Within the user and password field, any ":", "#", or "/" must be encoded.
The actual URL spec document does not explicitly mention encoding special characters in usernames and passwords, but I think it's implied that you can encode them. And it says
Because a % sign always indicates
an encoded character, a URL may be made safer simply by encoding
any characters considered unsafe, while leaving already encoded.
So you should percent-escape any special charaters in your URL, and in the case of an '#' that's %40.
Alternatively you could use the following classes provided by .net:
FtpWebRequest
WebRequestMethods
NetworkCredential
Private Shared Sub UploadFileToFTP(source As String)
Try
Dim filename As String = Path.GetFileName(source)
Dim ftpfullpath As String = ftpurl
Dim ftp As FtpWebRequest = DirectCast(FtpWebRequest.Create(ftpfullpath), FtpWebRequest)
ftp.Credentials = New NetworkCredential(ftpusername, ftppassword)
ftp.KeepAlive = True
ftp.UseBinary = True
ftp.Method = WebRequestMethods.Ftp.UploadFile
Dim fs As FileStream = File.OpenRead(source)
Dim buffer As Byte() = New Byte(fs.Length - 1) {}
fs.Read(buffer, 0, buffer.Length)
fs.Close()
Dim ftpstream As Stream = ftp.GetRequestStream()
ftpstream.Write(buffer, 0, buffer.Length)
ftpstream.Close()
Catch ex As Exception
Throw ex
End Try
End Sub

Download file from ftp if newer or different

I am trying to download a file from an ftp site only if it's newer than my local file. Can anyone help how to incorporate to check for the file properties? right now it downloads the file, but just need if newer. The purpose is to update a .mdb with the contents of the file, so don't want to download file and run an update everytime my app runs, only if the file is different. This is the code I am using:
Const localFile As String = "C:\version.xml"
Const remoteFile As String = "/version.xml"
Const host As String = "ftp://1.1.1.1"
Const username As String = "user"
Const password As String = "pwd"
Dim URI As String = host & remoteFile
Dim ftp As System.Net.FtpWebRequest = _
CType(FtpWebRequest.Create(URI), FtpWebRequest)
ftp.Credentials = New _
System.Net.NetworkCredential(username, password)
ftp.KeepAlive = False
ftp.UseBinary = True
ftp.Method = System.Net.WebRequestMethods.Ftp.DownloadFile
Using response As System.Net.FtpWebResponse = _
CType(ftp.GetResponse, System.Net.FtpWebResponse)
Using responseStream As IO.Stream = response.GetResponseStream
Using fs As New IO.FileStream(localFile, IO.FileMode.Create)
Dim buffer(2047) As Byte
Dim read As Integer = 0
Do
read = responseStream.Read(buffer, 0, buffer.Length)
fs.Write(buffer, 0, read)
Loop Until read = 0
responseStream.Close()
fs.Flush()
fs.Close()
End Using
responseStream.Close()
End Using
response.Close()
End Using
Any help is appreciated
Not sure if this answers your question but I am looking for a similar answer and came across this.
http://msdn.microsoft.com/en-us/library/system.io.fileinfo.aspx
Look into LastWriteTime and you could save that time and check to see if it is a newer date then what is saved. You would have to also figure out how to download the file as a while(not familiar with the code maybe you are).