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
One day, FileZilla decided not to let me download. (Right click, "Download" is gray), so I downloaded SmartFTP, but I didn't really like that.
So I asked myself, why not make one? So, I already have it half-working (can connect to ftp-servers, download, upload, moving in and out folders, and create directories), however, it can't open folders with accented and/or special characters in them (á, é, ö, #, etc.), and they also appear in the listbox like this: "Adatb?ziskezel?s", while the inbuilt stuff in windows shows it like this: "Adatbáziskezelés".
What could I do in order to make it work?
public string[] OpenFolder(string foldername)
{
byte[] bytes = Encoding.Default.GetBytes(foldername);
foldername = Encoding.UTF8.GetString(bytes);
string[] downloadFiles;
StringBuilder result = new StringBuilder();
FtpWebRequest reqFTP;
try
{
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(
"ftp://" + IP + "/"+foldername+"/"));
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential(username,
password);
reqFTP.Method = WebRequestMethods.Ftp.ListDirectory;
WebResponse response = reqFTP.GetResponse();
StreamReader reader = new StreamReader(response
.GetResponseStream());
string line = reader.ReadLine();
while (line != null)
{
result.Append(line);
result.Append("\n");
line = reader.ReadLine();
}
result.Remove(result.ToString().LastIndexOf('\n'), 1);
reader.Close();
response.Close();
return result.ToString().Split('\n');
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
downloadFiles = null;
return downloadFiles;
}
}
if (line.Contains("#"))
{
line = line.Replace("#", Uri.HexEscape('#'));
}
and so forth...
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.
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;
}
}
}
}
I'm creating a program where I need to search an FTP server and download all files which match a given regex. How do I do this? I can connect to the FTP server, but how do I scan all files in the given path for files matching the regex?
I also need to do the same for HTTP servers which I think will be fundamentally more difficult, but I'll stick to doing the FTP server for now.
Thanks
You can use this to get a list
public string[] GetFileList()
{
string[] downloadFiles;
StringBuilder result = new StringBuilder();
FtpWebRequest reqFTP;
try
{
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpServerIP + "/"));
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
reqFTP.Method = WebRequestMethods.Ftp.ListDirectory;
WebResponse response = reqFTP.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string line = reader.ReadLine();
while (line != null)
{
result.Append(line);
result.Append("\n");
line = reader.ReadLine();
}
// to remove the trailing '\n'
result.Remove(result.ToString().LastIndexOf('\n'), 1);
reader.Close();
response.Close();
return result.ToString().Split('\n');
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
downloadFiles = null;
return downloadFiles;
}
}
and then maipulate GetFileList Array using regex as per your need
FTP has a list (ls) command - any library you use should have a corresponding method, this will return a listing of files in the current directory.
You can match against this list and only retrieve the files that match.
Without knowing the exact library you are using, it is difficult to get more specific.