The output for FTP.ListDirectoryDetails is often a string similar to the one given below:
-rw-r--r-- 1 ftp ftp 960 Aug 31 09:09 test1.xml
How do I convert this into an object that is easy to use?
The output for FTP.ListDirectoryDetails is often a string similar to the one given below:
-rw-r--r-- 1 ftp ftp 960 Aug 31 09:09 test1.xml
How do I convert this into an object that is easy to use?
I could not find a decent solution for converting this into a useful object, so I created my own. I hope the code below helps someone else. If you have suggestions to improve this code, please feel free to contribute.
Here is the class:
/// <summary>
/// This class represents the file/directory information received via FTP.ListDirectoryDetails
/// </summary>
public class ListDirectoryDetailsOutput
{
public bool IsDirectory { get; set; }
public bool IsFile {
get { return !IsDirectory; }
}
//Owner permissions
public bool OwnerRead { get; set; }
public bool OwnerWrite { get; set; }
public bool OwnerExecute { get; set; }
//Group permissions
public bool GroupRead { get; set; }
public bool GroupWrite { get; set; }
public bool GroupExecute { get; set; }
//Other permissions
public bool OtherRead { get; set; }
public bool OtherWrite { get; set; }
public bool OtherExecute { get; set; }
public int NumberOfLinks { get; set; }
public int Size { get; set; }
public DateTime ModifiedDate { get; set; }
public string Name { get; set; }
public bool ParsingError { get; set; }
public Exception ParsingException { get; set; }
/// <summary>
/// Parses the FTP response for ListDirectoryDetails into the Output object
/// An example input of a file called test1.xml:
/// -rw-r--r-- 1 ftp ftp 960 Aug 31 09:09 test1.xml
/// </summary>
/// <param name="ftpResponseLine"></param>
public ListDirectoryDetailsOutput(string ftpResponseLine)
{
try
{
string[] responseList = ftpResponseLine.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
string permissions = responseList[0];
//Get directory, currently only checking for not "-", might be beneficial to also check for "d" when mapping IsDirectory
IsDirectory = !string.Equals(permissions.ElementAt(0), '-');
//Get directory, currently only checking for not "-", might be beneficial to also check for r,w,x when mapping permissions
//Get Owner Permissions
OwnerRead = !string.Equals(permissions.ElementAt(1), '-');
OwnerWrite = !string.Equals(permissions.ElementAt(2), '-');
OwnerExecute = !string.Equals(permissions.ElementAt(3), '-');
//Get Group Permissions
GroupRead = !string.Equals(permissions.ElementAt(4), '-');
GroupWrite = !string.Equals(permissions.ElementAt(5), '-');
GroupExecute = !string.Equals(permissions.ElementAt(6), '-');
//Get Other Permissions
OtherRead = !string.Equals(permissions.ElementAt(7), '-');
OtherWrite = !string.Equals(permissions.ElementAt(8), '-');
OtherExecute = !string.Equals(permissions.ElementAt(9), '-');
NumberOfLinks = int.Parse(responseList[1]);
Size = int.Parse(responseList[4]);
string dateStr = responseList[5] + " " + responseList[6] + " " + responseList[7];
//Setting Year to the current year, can be changed if needed
dateStr += " " + DateTime.Now.Year.ToString();
ModifiedDate = DateTime.ParseExact(dateStr, "MMM dd hh:mm yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces);
Name = (responseList[8]);
ParsingError = false;
}
catch (Exception ex)
{
ParsingException = ex;
ParsingError = true;
}
}
}
And here is how I use it:
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(FTPURL);
request.Credentials = new NetworkCredential(FTPUsername, FTPPassword);
//Only required for SFTP
//request.EnableSsl = true;
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
StreamReader streamReader = new StreamReader(response.GetResponseStream());
List<ListDirectoryDetailsOutput> directories = new List<ListDirectoryDetailsOutput>();
string line = streamReader.ReadLine();
while (!string.IsNullOrEmpty(line))
{
directories.Add(new ListDirectoryDetailsOutput(line));
line = streamReader.ReadLine();
}
streamReader.Close();
PLEASE NOTE: This will only work if the input string is exactly in the same format. If not, ParsingError will be true, and the exception will be caught as ParsingException.
Note 2: Files older than 1 year have the format MMM dd yyyy , not MMM dd hh:mm. This will require some tweaks in the code above. Missing year does not always mean current year (code given assumes that incorrectly). Missing year just means within the last year. When getting a file in April with the date Dec 20, missing year would mean last year, not this year. (Thanks Martin!)