列出FTP目录及其子目录中的文件名

时间:2016-12-12 21:58:35

标签: c# .net ftp ftpwebrequest

我在网上搜索过,但没有找到任何结果。实际上,我希望获得rootDirectory以及Sub Directory中所有文件的名称。我尝试了下面的代码但它只给了我FTP中root的文件。

我在FTP中的文件夹如下所示:

/ds/product/Jan/
/ds/subproduct/Jan/
/ds/category/Jan/

我尝试的代码:

FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create("ftp://" + FtpIP);
ftpRequest.Credentials = new NetworkCredential(FtpUser, FtpPass);
ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse();
StreamReader streamReader = new StreamReader(response.GetResponseStream());

List<string> directories = new List<string>();

string line = streamReader.ReadLine();
while (!string.IsNullOrEmpty(line))
{
   // directories.Add(line);
    line = streamReader.ReadLine().ToString();
    MessageBox.Show(line);
}

streamReader.Close();

1 个答案:

答案 0 :(得分:1)

在没有任何外部库的情况下实现它并不容易。不幸的是,.NET Framework和PowerShell都没有明确支持递归列出目录中的文件。

你必须自己实现:

  • 列出远程目录
  • 迭代条目,递归到子目录 - 再次列出它们等等。

棘手的部分是识别子目录中的文件。使用.NET框架(FtpWebRequest)以便携方式无法做到这一点。遗憾的是,.NET框架不支持MLSD命令,这是在FTP协议中使用文件属性检索目录列表的唯一可移植方式。另请参阅Checking if object on FTP server is file or directory

您的选择是:

  • 对文件名执行操作,该文件名对于文件肯定会失败并对目录成功(反之亦然)。即您可以尝试下载“名称”。
  • 您可能很幸运,在您的具体情况下,您可以通过文件名告诉目录中的文件(即所有文件都有扩展名,而子目录则没有)
  • 您使用长目录列表(LIST command = ListDirectoryDetails方法)并尝试解析特定于服务器的列表。许多FTP服务器使用* nix样式列表,您可以在条目的最开始通过d标识目录。但是许多服务器使用不同的格式。以下示例使用此方法(假设为* nix格式)
static void ListFtpDirectory(string url, NetworkCredential credentials)
{
    WebRequest listRequest = WebRequest.Create(url);
    listRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
    listRequest.Credentials = credentials;

    List<string> lines = new List<string>();

    using (WebResponse listResponse = listRequest.GetResponse())
    using (Stream listStream = listResponse.GetResponseStream())
    using (StreamReader listReader = new StreamReader(listStream))
    {
        while (!listReader.EndOfStream)
        {
            string line = listReader.ReadLine();
            lines.Add(line);
        }
    }

    foreach (string line in lines)
    {
        string[] tokens =
            line.Split(new[] { ' ' }, 9, StringSplitOptions.RemoveEmptyEntries);
        string name = tokens[8];
        string permissions = tokens[0];

        if (permissions[0] == 'd')
        {
            Console.WriteLine($"Directory {name}");

            string fileUrl = url + name;
            ListFtpDirectory(fileUrl + "/", credentials);
        }
        else
        {
            Console.WriteLine($"File {name}");
        }
    }
}

使用如下功能:

NetworkCredential credentials = new NetworkCredential("user", "mypassword");
string url = "ftp://ftp.example.com/directory/to/list/";
ListFtpDirectory(url, credentials);

如果您想避免解析特定于服务器的目录列表格式的麻烦,请使用支持MLSD命令和/或解析各种LIST列表格式的第三方库。

例如,使用WinSCP .NET assembly,您可以通过一次调用Session.EnumerateRemoteFiles递归地列出整个目录:

// Setup session options
var sessionOptions = new SessionOptions
{
    Protocol = Protocol.Ftp,
    HostName = "ftp.example.com",
    UserName = "user",
    Password = "mypassword",
};

using (var session = new Session())
{
    // Connect
    session.Open(sessionOptions);

    // Enumerate files
    var options =
        EnumerationOptions.EnumerateDirectories | EnumerationOptions.AllDirectories;
    IEnumerable<RemoteFileInfo> fileInfos =
        session.EnumerateRemoteFiles("/directory/to/list", null, options);
    foreach (var fileInfo in fileInfos)
    {
        Console.WriteLine(fileInfo.FullName);
    }
}

不仅代码更简单,更强大且与平台无关。它还可以通过RemoteFileInfo class轻松获取所有其他文件属性(大小,修改时间,权限,所有权)。

如果服务器支持,WinSCP在内部使用MLSD命令。如果没有,它使用LIST命令并支持许多不同的列表格式。

(我是WinSCP的作者)