List of files from ftp - c#

i have problem with this code..the code give me back this names of files:
"."
"orders00001.xml"
".."
"orders00010.xml"
But in the folder are only order00001 and order 00010.xml. Have you any idea where is the problem please?
private void getFileList()
{
List<string> files = new List<string>();
try
{
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(****);
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.Credentials = new NetworkCredential(**, **);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
while (!reader.EndOfStream)
{
Application.DoEvents();
files.Add(reader.ReadLine());
}
reader.Close();
responseStream.Close(); //redundant
response.Close();
}
catch (Exception)
{
MessageBox.Show("error connecting");
}
if (files.Count != 0)
{
foreach (string file in files)
{
//My code on work with xml
}
else
{
getFileList();
}
}

Directory management lists . and .. as virtual directories. The directory . points to itself allowing to refresh the directory. The directory .. directs you one directory up.
Filter these two directory entries when parsing your orders.
You may have seen directory paths like c:\windows..\Users which actually points to c:\Users as .. goes one directory hierarchy up.
Having a path pointing to .\Users means the directory Users in the current(.) directory.
You should always filter them out because if you are writing a recursive algorithm reading the directory "." will result in an infinite loop.

Related

Filenames missing from ListDirectoryDetails

I am trying to get all files in a ftp directory however I am having issues its not bringing back all files. But the first to files its not getting the file name for some weird reason so then my program skips it.
public static string[] GetFilesInDirectory(string requestUriString, string username, string password)
{
var lines = new List<string>();
try
{
// Get the object used to communicate with the server.
var request = (FtpWebRequest) WebRequest.Create(requestUriString);
request.Credentials = new NetworkCredential(username, password);
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.UsePassive = true;
using (WebResponse response = (FtpWebResponse) request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
{
using (var reader = new StreamReader(responseStream))
{
string line;
while ((line = reader.ReadLine()) != null)
{
try
{
lines.Add(line);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
}
}
}
catch (Exception ex)
{
throw new Exception("An error occured connecting to the website.", ex);
}
return lines.ToArray();
}
When I look at the files you wil see here that the first two are missing there names.
You will see that the file names are missing the count is correct but no idea why the file names are blank.
Sorry there are thirteen files so where is it even getting the extra two array entries.
Here is the files as well on the server as u see there is 13 files.
And here is my array of files.
They're not missing, you just didn't look closely enough. Single dot . represents the current directory and double dot .. represents the parent directory.
https://superuser.com/a/37451/255404

Get a list from FTP folder on web (port 80) to array

I'm trying to get a list of files from FTP web folder via port 80 into an array or list and then download specific extensions, but a counter is always zero for some reason.
public void GetFilesFromServer(string url, string extension=".mp3")
{
List<string> files = new List<string>();
try
{
//Create FTP request
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(url);
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.Credentials = new NetworkCredential("anonymous", "anonymous");
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
while (!reader.EndOfStream)
{
files.Add(reader.ReadLine());
}
//Clean-up
reader.Close();
responseStream.Close(); //redundant
response.Close();
}
catch (Exception)
{
// MessageBox.Show("There was an error connecting to the FTP Server");
}
//If the list was successfully received, display it to the user
//through a dialog
if (files.Count != 0)
{
string folderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DownloadedFiles");
WebClient wc = new WebClient();
foreach (string file in files)
{
if(file.EndsWith(extension))
wc.DownloadFile(url+"/"+file, Path.Combine(folderPath, file));
}
}
}
My goal is to put all .ext files into an array and I can't get the list
The folder is http://url.com/folder for example.
But it fails to request
I checked the solutions and it doesn't work for me.
The FtpWebRequest is for FTP protocol.
FTP protocol does not use port 80.
If your URL is an HTML presentation of a folder on the server, you cannot scrape it with FtpWebRequest. You have to parse the HTML.
Though you should better find a way to access the data using a more reliable method (such as using a real FTP).
The MS documentation says that the FtpWebRequest initializes a new WebRequest and according to the documentation here : https://msdn.microsoft.com/en-us/library/bw00b1dc(v=vs.110).aspx
then if the URL starts with "http://" you will get back an HttpWebRequest rather than a FtpWebRequest.
This answer may explain:
Getting directory listing over http

Downloading multiple files using FTP in C#

I need to write a routines that downloads a given directory on the server completely - all the files and directories in it.
Right now I have a routine that lists dir content
public List<string> GetListOfFiles(string serverPath)
{
List<string> files = new List<string>();
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" + serverPath);
request.Credentials = new NetworkCredential(_domain + "\\" + _username, _password);
request.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string line = reader.ReadLine();
while (line != null)
{
files.Add(line);
line = reader.ReadLine();
}
response.Close();
}
catch (WebException ex)
{
FtpWebResponse response = (FtpWebResponse)ex.Response;
string exMsg = string.Empty;
switch (response.StatusCode)
{
case FtpStatusCode.NotLoggedIn:
exMsg = "wrong username/password";
break;
default:
exMsg = "The server is inaccessible or taking too long to respond.";
break;
}
throw new Exception(exMsg);
}
return files;
}
The issue is that I get the list of files and directories...so something like
file1.dll
file2.dll
dir1Name
Is there a way to make a distinction between a file name and a directory name when listing it? Like a flag?
Unfortunately, the returned information is really a function of your FTP server, not the framework.
You can ListDirectoryDetails instead of ListDirectory, which should provide you much more detailed information (including whether each file is a directory or a file), but would require special parsing, as its format, too, is dependent on the FTP Server.

How to recursively delete a folder with the files within using FtpWebRequest?

I want to delete a folder in FTP and it's files recursively.
Any example code do I can implement?
First you have to list all your files in your directory :
public static List<string> DirectoryListing(string Path, string ServerAdress, string Login, string Password)
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" + ServerAdress + Path);
request.Credentials = new NetworkCredential(Login, Password);
request.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
List<string> result = new List<string>();
while (!reader.EndOfStream)
{
result.Add(reader.ReadLine());
}
reader.Close();
response.Close();
return result;
}
Then you need a method to delete a single file (because you can delete a folder only if it's empty) :
public static void DeleteFTPFile(string Path, string ServerAdress, string Login, string Password)
{
FtpWebRequest clsRequest = (System.Net.FtpWebRequest)WebRequest.Create("ftp://" + ServerAdress + Path);
clsRequest.Credentials = new System.Net.NetworkCredential(Login, Password);
clsRequest.Method = WebRequestMethods.Ftp.DeleteFile;
string result = string.Empty;
FtpWebResponse response = (FtpWebResponse)clsRequest.GetResponse();
long size = response.ContentLength;
Stream datastream = response.GetResponseStream();
StreamReader sr = new StreamReader(datastream);
result = sr.ReadToEnd();
sr.Close();
datastream.Close();
response.Close();
}
And finally :
public static void DeleteFTPDirectory(string Path, string ServerAdress, string Login, string Password)
{
FtpWebRequest clsRequest = (System.Net.FtpWebRequest)WebRequest.Create("ftp://" + ServerAdress + Path);
clsRequest.Credentials = new System.Net.NetworkCredential(Login, Password);
List<string> filesList = DirectoryListing(Path, ServerAdress, Login, Password);
foreach (string file in filesList)
{
DeleteFTPFile(Path + file, ServerAdress, Login, Password);
}
clsRequest.Method = WebRequestMethods.Ftp.RemoveDirectory;
string result = string.Empty;
FtpWebResponse response = (FtpWebResponse)clsRequest.GetResponse();
long size = response.ContentLength;
Stream datastream = response.GetResponseStream();
StreamReader sr = new StreamReader(datastream);
result = sr.ReadToEnd();
sr.Close();
datastream.Close();
response.Close();
}
You can easily call this like that (for me those methods are in a class called "Ftp") :
Ftp.DeleteFTPDirectory(the_path_of_your_folder_in_ftp,your_server_address,your_ftp_login,your_ftp_password);
Of course, you'll need to customize those lines, but it worked perfectly for me :)
There's no support for recursive operations in the FtpWebRequest class (or any other FTP implementation in the .NET framework). You have to implement the recursion yourself:
List the remote directory
Iterate the entries, deleting files and recursing into subdirectories (listing them again, etc.)
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 a file and to succeed for directory (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. But that can become a performance problem, when you have a large number of entries.
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).
In this specific case, you can just try to delete the entry as a file. If deleting fails, try to list the entry as a directory. If the listing succeeds, you assume it's a folder and proceed accordingly. Unfortunately some servers do not error, when you try to list a file. They will just return a listing with a single entry for the file.
static void DeleteFtpDirectory(string url, NetworkCredential credentials)
{
FtpWebRequest listRequest = (FtpWebRequest)WebRequest.Create(url);
listRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
listRequest.Credentials = credentials;
List<string> lines = new List<string>();
using (FtpWebResponse listResponse = (FtpWebResponse)listRequest.GetResponse())
using (Stream listStream = listResponse.GetResponseStream())
using (StreamReader listReader = new StreamReader(listStream))
{
while (!listReader.EndOfStream)
{
lines.Add(listReader.ReadLine());
}
}
foreach (string line in lines)
{
string[] tokens =
line.Split(new[] { ' ' }, 9, StringSplitOptions.RemoveEmptyEntries);
string name = tokens[8];
string permissions = tokens[0];
string fileUrl = url + name;
if (permissions[0] == 'd')
{
DeleteFtpDirectory(fileUrl + "/", credentials);
}
else
{
FtpWebRequest deleteRequest = (FtpWebRequest)WebRequest.Create(fileUrl);
deleteRequest.Method = WebRequestMethods.Ftp.DeleteFile;
deleteRequest.Credentials = credentials;
deleteRequest.GetResponse();
}
}
FtpWebRequest removeRequest = (FtpWebRequest)WebRequest.Create(url);
removeRequest.Method = WebRequestMethods.Ftp.RemoveDirectory;
removeRequest.Credentials = credentials;
removeRequest.GetResponse();
}
The url should be like ftp://example.com/directory/to/delete/
Or use a 3rd party library that supports recursive operations.
For example with WinSCP .NET assembly you can delete whole directory with a single call to Session.RemoveFiles:
// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Ftp,
HostName = "example.com",
UserName = "user",
Password = "mypassword",
};
using (Session session = new Session())
{
// Connect
session.Open(sessionOptions);
// Delete folder
session.RemoveFiles("/home/user/foldertoremove").Check();
}
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.
(I'm the author of WinSCP)
Nice Little example you can find here:
http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.aspx
In the example they used WebRequestMethods.Ftp.UploadFile class to direct what kind of operation they want to do.
Use the WebRequestMethods.Ftp.RemoveDirectory method once you have a handle on the parent directory you want to delete:
http://msdn.microsoft.com/en-us/library/system.net.webrequestmethods.ftp.aspx
None of the solutions really worked on different types of servers except using
System.Net.FtpClient
using System.Net.FtpClient;
static void DeleteFtpDirectoryAndContent(string host, string path, NetworkCredential credentials, string dontDeleteFileUrl)
{
using (FtpClient conn = new FtpClient())
{
conn.Host = host;
conn.Credentials = credentials;
foreach (FtpListItem item in conn.GetListing(path, FtpListOption.AllFiles | FtpListOption.ForceList))
{
switch (item.Type)
{
case FtpFileSystemObjectType.Directory:
conn.DeleteDirectory(item.FullName, true, FtpListOption.AllFiles | FtpListOption.ForceList);
break;
case FtpFileSystemObjectType.File:
if (!dontDeleteFileUrl.EndsWith(item.FullName, StringComparison.InvariantCultureIgnoreCase))
conn.DeleteFile(item.FullName);
break;
}
}
}
}

How to check if an FTP directory exists

Looking for the best way to check for a given directory via FTP.
Currently i have the following code:
private bool FtpDirectoryExists(string directory, string username, string password)
{
try
{
var request = (FtpWebRequest)WebRequest.Create(directory);
request.Credentials = new NetworkCredential(username, password);
request.Method = WebRequestMethods.Ftp.GetDateTimestamp;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
FtpWebResponse response = (FtpWebResponse)ex.Response;
if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
return false;
else
return true;
}
return true;
}
This returns false whether the directory is there or not. Can someone point me in the right direction.
Basically trapped the error that i receive when creating the directory like so.
private bool CreateFTPDirectory(string directory) {
try
{
//create the directory
FtpWebRequest requestDir = (FtpWebRequest)FtpWebRequest.Create(new Uri(directory));
requestDir.Method = WebRequestMethods.Ftp.MakeDirectory;
requestDir.Credentials = new NetworkCredential("username", "password");
requestDir.UsePassive = true;
requestDir.UseBinary = true;
requestDir.KeepAlive = false;
FtpWebResponse response = (FtpWebResponse)requestDir.GetResponse();
Stream ftpStream = response.GetResponseStream();
ftpStream.Close();
response.Close();
return true;
}
catch (WebException ex)
{
FtpWebResponse response = (FtpWebResponse)ex.Response;
if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
{
response.Close();
return true;
}
else
{
response.Close();
return false;
}
}
}
The complete solution will now be:
public bool DoesFtpDirectoryExist(string dirPath)
{
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(dirPath);
request.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
return true;
}
catch(WebException ex)
{
return false;
}
}
// Calling the method (note the forwardslash at the end of the path):
string ftpDirectory = "ftp://ftpserver.com/rootdir/test_if_exist_directory/";
bool dirExists = DoesFtpDirectoryExist(ftpDirectory);
Originally, I was using,
string ftpDirectory = "ftp://ftpserver.com/rootdir/test_if_exist_directory";
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpDirectory);
request.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
and waited for an exception in case the directory didn't exist. This method didn't throw an exception.
After a few hit and trials, I changed the directory from:
ftp://ftpserver.com/rootdir/test_if_exist_directory
to:
ftp://ftpserver.com/rootdir/test_if_exist_directory/
Now the code is working for me.
I think we should append a forward slash (/) to the URI of the FTP folder to get it to work.
I assume that you are already somewhat familiar with FtpWebRequest, as this is the usual way to access FTP in .NET.
You can attempt to list the directory and check for an error StatusCode.
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftp.microsoft.com/12345");
request.Method = WebRequestMethods.Ftp.ListDirectory;
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
{
// Okay.
}
}
catch (WebException ex)
{
if (ex.Response != null)
{
FtpWebResponse response = (FtpWebResponse)ex.Response;
if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
{
// Directory not found.
}
}
}
I would try something along this lines:
Send MLST <directory> FTP command (defined in RFC3659) and parse it's output. It should return valid line with directory details for existing directories.
If MLST command is not available, try changing the working directory into the tested directory using a CWD command. Don't forget to determine the current path (PWD command) prior to changing to a tested directory to be able to go back.
On some servers combination of MDTM and SIZE command can be used for similar purpose, but the behavior is quite complex and out of scope of this post.
This is basically what DirectoryExists method in the current version of our Rebex FTP component does. The following code shows how to use it:
string path = "/path/to/directory";
Rebex.Net.Ftp ftp = new Rebex.Net.Ftp();
ftp.Connect("hostname");
ftp.Login("username","password");
Console.WriteLine(
"Directory '{0}' exists: {1}",
path,
ftp.DirectoryExists(path)
);
ftp.Disconnect();
User this code it may be your answer..
public bool FtpDirectoryExists(string directoryPath, string ftpUser, string ftpPassword)
{
bool IsExists = true;
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(directoryPath);
request.Credentials = new NetworkCredential(ftpUser, ftpPassword);
request.Method = WebRequestMethods.Ftp.PrintWorkingDirectory;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
IsExists = false;
}
return IsExists;
}
I have called this method as:
bool result = FtpActions.Default.FtpDirectoryExists( #"ftp://mydomain.com/abcdir", txtUsername.Text, txtPassword.Text);
Why use another library - create your own logic's.
I tried every which way to get a solid check but neither the WebRequestMethods.Ftp.PrintWorkingDirectory nor WebRequestMethods.Ftp.ListDirectory methods would work correctly. They failed when checking for ftp://<website>/Logs which doesnt exist on the server but they say it does.
So the method I came up with was to try to upload to the folder. However, one 'gotcha' is the path format which you can read about in this thread Uploading to Linux
Here is a code snippet
private bool DirectoryExists(string d)
{
bool exists = true;
try
{
string file = "directoryexists.test";
string path = url + homepath + d + "/" + file;
//eg ftp://website//home/directory1/directoryexists.test
//Note the double space before the home is not a mistake
//Try to save to the directory
req = (FtpWebRequest)WebRequest.Create(path);
req.ConnectionGroupName = "conngroup1";
req.Method = WebRequestMethods.Ftp.UploadFile;
if (nc != null) req.Credentials = nc;
if (cbSSL.Checked) req.EnableSsl = true;
req.Timeout = 10000;
byte[] fileContents = System.Text.Encoding.Unicode.GetBytes("SAFE TO DELETE");
req.ContentLength = fileContents.Length;
Stream s = req.GetRequestStream();
s.Write(fileContents, 0, fileContents.Length);
s.Close();
//Delete file if successful
req = (FtpWebRequest)WebRequest.Create(path);
req.ConnectionGroupName = "conngroup1";
req.Method = WebRequestMethods.Ftp.DeleteFile;
if (nc != null) req.Credentials = nc;
if (cbSSL.Checked) req.EnableSsl = true;
req.Timeout = 10000;
res = (FtpWebResponse)req.GetResponse();
res.Close();
}
catch (WebException ex)
{
exists = false;
}
return exists;
}
Navigate to the parent directory, execute the "ls" command, and parse the result.
I couldn't get this #BillyLogans suggestion to work....
I found the problem was the default FTP directory was /home/usr/fred
When I used:
String directory = "ftp://some.domain.com/mydirectory"
FtpWebRequest requestDir = (FtpWebRequest)FtpWebRequest.Create(new Uri(directory));
I found this gets turned into
"ftp:/some.domain.com/home/usr/fred/mydirectory"
to stop this change the directory Uri to:
String directory = "ftp://some.domain.com//mydirectory"
Then this starts working.
This was my best. get list from parent dir, and check if parent have correct child name
public void TryConnectFtp(string ftpPath)
{
string[] splited = ftpPath.Split('/');
StringBuilder stb = new StringBuilder();
for (int i = 0; i < splited.Length - 1; i++)
{
stb.Append(splited[i] +'/');
}
string parent = stb.ToString();
string child = splited.Last();
FtpWebRequest testConnect = (FtpWebRequest)WebRequest.Create(parent);
testConnect.Method = WebRequestMethods.Ftp.ListDirectory;
testConnect.Credentials = credentials;
using (FtpWebResponse resFtp = (FtpWebResponse)testConnect.GetResponse())
{
StreamReader reader = new StreamReader(resFtp.GetResponseStream());
string result = reader.ReadToEnd();
if (!result.Contains(child) ) throw new Exception("###");
resFtp.Close();
}
}
The only way which worked for me was an inversed logic by trying to create the directory/path (which will throw an exception if it already exists) and if so delete it again afterwards. Otherwise use the Exception to set a flag meaing that the directory/path exists. I'm quite new to VB.NET and I'm shure there's a nicer way to code this - but anyway here's my code:
Public Function DirectoryExists(directory As String) As Boolean
' Reversed Logic to check if a Directory exists on FTP-Server by creating the Directory/Path
' which will throw an exception if the Directory already exists. Otherwise create and delete the Directory
' Adjust Paths
Dim path As String
If directory.Contains("/") Then
path = AdjustDir(directory) 'ensure that path starts with a slash
Else
path = directory
End If
' Set URI (formatted as ftp://host.xxx/path)
Dim URI As String = Me.Hostname & path
Dim response As FtpWebResponse
Dim DirExists As Boolean = False
Try
Dim request As FtpWebRequest = DirectCast(WebRequest.Create(URI), FtpWebRequest)
request.Credentials = Me.GetCredentials
'Create Directory - if it exists WebException will be thrown
request.Method = WebRequestMethods.Ftp.MakeDirectory
'Delete Directory again - if above request did not throw an exception
response = DirectCast(request.GetResponse(), FtpWebResponse)
request = DirectCast(WebRequest.Create(URI), FtpWebRequest)
request.Credentials = Me.GetCredentials
request.Method = WebRequestMethods.Ftp.RemoveDirectory
response = DirectCast(request.GetResponse(), FtpWebResponse)
DirExists = False
Catch ex As WebException
DirExists = True
End Try
Return DirExists
End Function
WebRequestMethods.Ftp.MakeDirectory and WebRequestMethods.Ftp.RemoveDirectory are the Methods i used for this. All other solutions did not work for me.
Hope it helps
For what it is worth, You'll make your FTP life quite a bit easier if you use EnterpriseDT's FTP component. It's free and will save you headaches because it deals with the commands and responses. You just work with a nice, simple object.

Categories