检查FTP上的文件或文件夹

时间:2017-08-30 08:24:23

标签: c# .net ftp ftpwebrequest

我从FTP读取文件/文件夹列表。

问题是我不知道是文件还是文件夹。 目前我正在检查字符串是否有扩展名。如果是,那么它是文件,否则它是文件夹。但这还不够好,它可以存在没有扩展名的文件和带扩展名的文件夹(例如文件夹名称可以是FolderName.TXT)

这是我用来列出文件夹内容的代码:

public async Task<CollectionResult<string>> ListFolder(string path)
{
    try
    {
        FtpWebRequest ftpRequest = null;
        var fileNames = new List<string>();
        var res = new CollectionResult<string>();
        ftpRequest = ftpBuilder.Create(path, WebRequestMethods.Ftp.ListDirectory);
        using (var ftpResponse = (FtpWebResponse)await ftpRequest.GetResponseAsync())
        using (var ftpStream = ftpResponse.GetResponseStream())
        using (var streamReader = new StreamReader(ftpStream, Encoding.UTF8))
        {
            string fileName = streamReader.ReadLine();
            while (!string.IsNullOrEmpty(fileName))
            {
                fileNames.Add(Path.Combine(path, fileName.Substring(fileName.IndexOf('/') + 1, fileName.Length - fileName.IndexOf('/') - 1)));
                fileName = streamReader.ReadLine();
            }
        }
        ftpRequest = null;
        res.ListResult = fileNames;
        return res;
    }
    catch (Exception e)
    {
        e.AddExceptionParameter(this, nameof(path), path);
        throw;
    }
}

最好是我可以在循环中检测文件或文件夹是否存在,但是不可能只是从字符串中执行此操作。

感谢您的帮助。

修改

我发现了类似的问题。 C# FTP, how to check if a Path is a File or a Directory? 但问题很严重,并没有很好的解决方案。

编辑:解决方案

 public async Task<CollectionResult<Tuple<string, bool>>> ListFolder(string path)
        {
            try
            {
                FtpWebRequest ftpRequest = null;
                var fileNames = new CollectionResult<Tuple<string, bool>>();
                fileNames.ListResult = new List<Tuple<string, bool>>();
                if (!(IsFtpDirectoryExist(path)))
                {
                    throw new RemoteManagerWarningException(ErrorKey.LIST_DIRECTORY_ERROR, fileNames.ErrorMessage = $"path folder {path} not exists");
                }
                ftpRequest = ftpBuilder.Create(path, WebRequestMethods.Ftp.ListDirectoryDetails);
                using (var ftpResponse = (FtpWebResponse)await ftpRequest.GetResponseAsync())
                using (var ftpStream = ftpResponse.GetResponseStream())
                using (var streamReader = new StreamReader(ftpStream, Encoding.UTF8))
                {
                    while (!streamReader.EndOfStream)
                    {
                        string line = streamReader.ReadLine();
                        string[] tokens = line.Split(new[] { ' ' }, 9, StringSplitOptions.RemoveEmptyEntries);
                        // is number:
                        Regex rgx = new Regex(@"^[\d\.]+$");
                        var isExternalFtpOrUnixDirectoryStyle = !(rgx.IsMatch(line[0].ToString()));
                        string name = string.Empty;
                        bool isFolder = false;

                        if (isExternalFtpOrUnixDirectoryStyle)
                        {
                            name = tokens[8];
                            var permissions = tokens[0];
                            isFolder = permissions[0] == 'd';
                        }
                        else
                        {
                            tokens = line.Split(new[] { ' ' }, 4, StringSplitOptions.RemoveEmptyEntries);
                            name = tokens[3];
                            isFolder = tokens[2] == "<DIR>";
                        }
                        name = Path.Combine(path, name);
                        Tuple<string, bool> tuple = new Tuple<string, bool>(name, isFolder);
                        fileNames.ListResult.Add(tuple);                           
                    }
                }
                ftpRequest = null;
                return fileNames;
            }
            catch (Exception e)
            {
                e.AddExceptionParameter(this, nameof(path), path);
                throw;
            }
        }

2 个答案:

答案 0 :(得分:2)

无法使用FtpWebRequest或.NET框架的任何其他内置功能以可移植的方式识别目录条目是否是文件的子目录。遗憾的是,FtpWebRequest不支持MLSD命令,这是在FTP协议中检索具有文件属性的目录列表的唯一可移植方式。另请参阅Checking if object on FTP server is file or directory

您的选择是:

  • 对某个文件名执行操作,该文件名对于文件肯定会失败并对目录成功(反之亦然)。即您可以尝试下载&#34;名称&#34;。如果成功,它就是一个文件,如果失败,它就是一个目录。
  • 您可能很幸运,在您的具体情况下,您可以通过文件名告诉目录中的文件(即所有文件都有扩展名,而子目录则没有)
  • 您使用长目录列表(LIST command = ListDirectoryDetails方法)并尝试解析特定于服务器的列表。许多FTP服务器使用* nix样式列表,您可以在条目的最开始通过d标识目录。但是许多服务器使用不同的格式。

    有关实现解析的一些示例,请参阅:
    * nix格式:Parsing FtpWebRequest ListDirectoryDetails line
    DOS / Windows格式:C# class to parse WebRequestMethods.Ftp.ListDirectoryDetails FTP response

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

例如,使用WinSCP .NET assembly,您可以使用Sesssion.ListDirectory

// 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);

    RemoteDirectoryInfo directory = session.ListDirectory("/home/martin/public_html");

    foreach (RemoteFileInfo fileInfo in directory.Files)
    {
        if (fileInfo.IsDirectory)
        {
            // directory
        }
        else
        {
            // file
        }
    }
}

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

(我是WinSCP的作者)

答案 1 :(得分:1)

使用FTP&#39; list&#39;命令并解析权限和目录指示符。