Filenames missing from ListDirectoryDetails - c#

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

Related

FTP client in WPF C# won't open folders with accented characters

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...

List of files from ftp

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.

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.

Searching all files for regex matching files on FTP server in C#.NET

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.

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