Skip to content

Instantly share code, notes, and snippets.

@derekantrican
Last active May 3, 2020 03:29
Show Gist options
  • Save derekantrican/9e890c06ed17ddc561d8af02e41c34c8 to your computer and use it in GitHub Desktop.
Save derekantrican/9e890c06ed17ddc561d8af02e41c34c8 to your computer and use it in GitHub Desktop.
Retrieve directory listing information from FTP
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
namespace FTPHelper
{
public class FTPItem
{
public char[] Permissions { get; set; }
public int Size { get; set; }
public DateTime LastModified { get; set; }
public string Name { get; set; }
public string FullPath { get; set; }
public override string ToString()
{
return Name;
}
}
public class FTPDirectory : FTPItem
{
public FTPDirectory(FTPItem item)
{
Permissions = item.Permissions;
Size = item.Size;
LastModified = item.LastModified;
Name = item.Name;
FullPath = item.FullPath;
}
public Lazy<List<FTPItem>> SubItems { get; set; }
}
public class FTPFile : FTPItem
{
public FTPFile(FTPItem item)
{
Permissions = item.Permissions;
Size = item.Size;
LastModified = item.LastModified;
Name = item.Name;
FullPath = item.FullPath;
}
}
public class FTPClient
{
private string address;
private string username;
private string password;
public FTPClient(string address, string username, string password)
{
this.address = address.StartsWith("ftp://", StringComparison.OrdinalIgnoreCase) ? address : $"ftp://{address}";
this.username = username;
this.password = password;
}
public List<FTPItem> RetrieveDirectoryListingsFromFTP(string startingPath = null)
{
List<FTPItem> results = new List<FTPItem>();
string path = !string.IsNullOrEmpty(startingPath) ? startingPath.Replace(" ", "%20") : address;
path = !path.StartsWith(address) ? $"{address}/{path}" : path;
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(path);
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.Credentials = new NetworkCredential(username, password);
request.KeepAlive = false;
request.UseBinary = true;
request.UsePassive = true;
Regex directoryListingRegex = new Regex(@"^([d-])((?:[rwxt-]{3}){3})\s+\d{1,}\s+.*?(\d{1,})\s+(\w+)\s+(\d{1,2})\s+(\d{4})?(\d{1,2}:\d{2})?\s+(.+?)\s?$",
RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(responseStream))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Match match = directoryListingRegex.Match(line);
FTPItem item = new FTPItem
{
Permissions = match.Groups[2].Value.ToArray(),
Size = int.Parse(match.Groups[3].Value),
LastModified = DateTime.ParseExact($"{match.Groups[4]} {match.Groups[5]} {match.Groups[6]} {match.Groups[7]}",
$"MMM dd {(match.Groups[6].Value != "" ? "yyyy" : "")} {(match.Groups[7].Value != "" ? "HH:mm" : "")}",
CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal),
Name = match.Groups[8].Value,
FullPath = $"{path}/{match.Groups[8].Value.Replace(" ", "%20")}",
};
if (match.Groups[1].Value == "d")
{
FTPDirectory dir = new FTPDirectory(item);
dir.SubItems = new Lazy<List<FTPItem>>(() => RetrieveDirectoryListingsFromFTP(dir.FullPath));
results.Add(dir);
}
else
{
FTPFile file = new FTPFile(item);
results.Add(file);
}
}
}
}
}
return results;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment