如何判断 FTP 目录是不是存在

Posted

技术标签:

【中文标题】如何判断 FTP 目录是不是存在【英文标题】:How to Determine if FTP Directory Exists如何判断 FTP 目录是否存在 【发布时间】:2014-07-15 15:00:25 【问题描述】:

我编写了以下代码来检测目录是否存在。 DirectoryExists 方法接受完全限定路径或相对路径。

public bool DirectoryExists(string directory)

    try
    
        FtpWebRequest request = GetRequest(directory);
        request.Method = WebRequestMethods.Ftp.ListDirectory;

        using (FtpWebResponse response = request.GetResponse() as FtpWebResponse)
        using (StreamReader sr = new StreamReader(response.GetResponseStream(), System.Text.Encoding.ASCII))
        
            sr.ReadToEnd();
        
        return true;
    
    catch  
    return false;


protected FtpWebRequest GetRequest(string filename = "")

    FtpWebRequest request = WebRequest.Create(_host.GetUrl(filename)) as FtpWebRequest;
    request.Credentials = new NetworkCredential(Username, Password);
    request.Proxy = null;
    request.KeepAlive = false;
    return request;

注意:_host.GetUrl(filename) 返回指定目录或文件名的完全限定路径。就我而言,这是ftp://www.mydomain.com/Articles/controls/precisely-defining-kilobytes-megabytes-and-gigabytes

这段代码已经运行了好几个月。但是突然之间它停止了工作。现在,当目录不存在时,DirectoryExists 不会引发异常。 sr.ReadToEnd() 只是返回一个空字符串。

我发布了一个类似的问题,有人建议我始终将/ 附加到路径的末尾。我试过了,以为我有一次异常,但现在没有引发异常。

我不知道我正在与之通信的 FTP 服务器上的行为是否发生了变化。同样,当我编写它时它运行良好,但现在它没有。

如何判断 FTP 目录是否存在?

编辑:

调用ReadToEnd()后查看响应,我看到了:

BannerMessage="220 Microsoft FTP 服务\r\n"

内容长度=-1

ExitMessage="221 再见。\r\n"

StatusCode=ClosingData

StatusDescription="226 传输完成。\r\n"

WelcomeMessage="230 用户已登录。\r\n"

更新:

最终,我发现大多数人一直在推荐我最初所做的事情的变体。这让 Hans Passant 认为问题出在服务器上的建议更有分量。我试图让他们看看这个,但他们似乎对整个讨论感到有点困惑。我知道他们使用的是 Microsoft 服务器,但我怀疑能否从他们那里得到解决方案。

如果所有其他方法都失败了,我认为答案是列出父目录,这确实需要一些额外的工作来处理一些情况,例如当有问题的目录是根目录时,以及父目录不是'不存在。

【问题讨论】:

可能与***.com/questions/2769137/…重复 是的,但对我来说,这些建议似乎都不起作用。 别跟我们说话,跟管理服务器的人说话。 只有当 FTP 服务器可靠时,您才能期待可靠性。当然,只有他才能修复此服务器以使其再次正常运行。如果您依赖另一台机器来让您的软件可靠运行,那么了解管理该机器的人非常重要。 @Jonathan Wood:我遇到了一个 FTP 服务器,它在发送用户名和密码之间需要一秒钟的延迟。您会为每个 FTP 服务器减慢代码,还是仅在检测到行为不端的服务器时添加代码以减慢速度?还有一种很好、快速和标准化的方式来获取 FTP 目录列表(MLSD 扩展名)。不幸的是,某些 FTP 服务器不支持它。另一种方法是猜测使用了哪种人类可读的列表格式并尝试解析它(通常是模棱两可的)。您会在可用时使用高级方法,还是使用旧方法? 【参考方案1】:

当您请求不存在的目录/文件时,FTP 服务器会回复 550 消息。这 550 在 .NET 中被转换为异常。

关于您提供的代码,我看不出在生产中使用 StreamReader 的原因。一个简单的修改如下:

public bool DirectoryExists(string directory)

  try
  
    FtpWebRequest request = GetRequest(directory);
    request.Method = WebRequestMethods.Ftp.ListDirectory;
    return request.GetResponse() != null;
  
  catch
  
    return false;
  

我将异常处理保持原样(缺失),但我建议您继续处理它,因为有许多不同的情况需要捕获,这些情况与 ftp 响应无关。

如果目录不存在,request.GetResponse() 会产生异常。

我尝试了以下路径以获得真正的回报:

ftp://ftp.mozilla.org/ ftp://ftp.mozilla.org/pub/ ftp://ftp.mozilla.org/pub/data/ ftp://ftp.mozilla.org/pub/data/bloat-reports/

最后一个是现有但为空的目录

ftp://ftp.mozilla.org/pub/data/bloat-reports2/ 返回错误

路径中有一个很大但关于尾随 / 的问题。

mozilla.org是pub目录下的零字节长度文件

ftp://ftp.mozilla.org/pub/mozilla.org 返回真

ftp://ftp.mozilla.org/pub/mozilla.org/ 返回 false 然后返回 true ?????

此行为与您所描述的相似。您可以轻松地在浏览器上重现它。我建议您对自己的路径执行相同的操作并检查目录的内容。如果您确实有空文件,请将其删除或将其内容替换为空格,最后检查您的代码以确保您不会创建新文件或以零字节长度重新创建它们。

我希望这会有所帮助。

更新

没有消息,坏消息!我认为上述内容对您没有任何帮助。也许通过在你的道路上上一层楼来解决问题。这个想法是获取父目录的列表并检查它的子名称。如果父路径有效,它应该总是返回非空字符串。代码如下:

static bool DirectoryExists(string directory)

    try
    
        directory = GetRequest(directory);
        string
            parent = directory.Substring(0, directory.TrimEnd('/').LastIndexOf('/') + 1),
            child = directory.Substring(directory.TrimEnd('/').LastIndexOf('/') + 1).TrimEnd('/');
        FtpWebRequest request = GetRequest(parent);
        request.Method = WebRequestMethods.Ftp.ListDirectory;
        using (FtpWebResponse response = request.GetResponse() as FtpWebResponse)
        
            if (response == null)
                return false;
            string data = new StreamReader(response.GetResponseStream(), true).ReadToEnd();
            return data.IndexOf(child, StringComparison.InvariantCultureIgnoreCase) >= 0;
        
    
    catch
    
        return false;
    

如您所见,无需担心尾随斜杠。

警告:代码不会涵盖同一路径下子目录和文件名相同的情况。

【讨论】:

虽然您的第一个代码块似乎包含一些改进,但它基本上与我的代码做同样的事情。也就是说,它依赖于在为不存在的目录调用WebRequestMethods.Ftp.ListDirectory 时引发的异常。不幸的是,结果也是一样的。就我而言,没有抛出异常。另外,GetResponse() 的结果是一个空字符串,而不是 null。 至于你的第二个建议,我已经考虑过了。当然,当给定目录是根目录时,这种方法会失效。如果我无法获得其他解决方案,我可能会尝试类似的方法。我已经联系了托管服务器的人,看看那里是否发生了任何奇怪的事情。 第一种方法将零字节长度文件的情况作为潜在原因。没有消息是第二个信号。您对根目录是正确的,但它与您组织路径的方式(/articles/controls/...)无关。将其视为针对您的特定案例的直接解决方法,而不是作为全球建议的解决方案。 我认为这是最有帮助的回应,我会奖励它。我更新了我的问题,以表明我对最佳方法的总体印象。【参考方案2】:

这可能是因为您的服务器上安装了 FTP 服务器软件。

否则,您可能需要查看 response.StatusCode 以查看是否有任何提示。

http://msdn.microsoft.com/en-us/library/system.net.ftpstatuscode(v=vs.110).aspx

最后,如果所有这些都不起作用,请尝试在该不存在的目录上编写一个哑文本文件。

【讨论】:

我更新了我的问题以显示response 的一些属性值是什么,包括StatusCode【参考方案3】:

我有类似的代码,可以通过 FTP 将项目部署到 IIS 6/Windows 2003 服务器。在我将它指向 IIS7/Windows 2008 服务器之前,它运行良好。我开始看到与您完全相同的行为。我对其进行了调试,最终将我的代码更改为以下内容。这是我的代码中的直接 sn-p。如果您愿意,我可以包含它调用的方法的来源,但我认为您了解这些操作。

try

    //Get a recursive FTP Listing
    items = GetFtpListing(target, true);

catch(WebException e)

    if (string.Equals(e.Message, "The remote server returned an error: (550) File unavailable (e.g., file not found, no access)."))
    
        CreateRemoteDirectory(target);
        items = GetFtpListing(target, true);
    
    else
    
        throw e;
    

GetFtpListing的相关部分

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

FtpWebRequest request = (FtpWebRequest)WebRequest.Create(path);
request.Timeout = 60000;
request.ReadWriteTimeout = 60000;
request.Credentials = this.credentials;
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;

using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())

    Stream data = response.GetResponseStream();

    using (StreamReader reader = new StreamReader(data))
    
        string responseString = reader.ReadToEnd();
        ftpRawList.AddRange(responseString.Split(new char[2]  '\r', '\n' , StringSplitOptions.RemoveEmptyEntries));
    

【讨论】:

我不确定我是否在这里看到了修复。基本上,您似乎使用的是WebRequestMethods.Ftp.ListDirectoryDetails 而不是WebRequestMethods.Ftp.ListDirectory。我确实尝试过并且得到了相同的结果。我不清楚这其中的哪一部分解决了您所看到的问题。 if (string.Equals(e.Message, "The remote server returned an error: (550) File unavailable (e.g., file not found, no access).")) CreateRemoteDirectory(target); items = GetFtpListing(target, true); 修复了它,特别是检查 550 并在目录不存在时创建目录(因为在我的模型中,我正在创建我们上传文件的结构。跨度> 好的,谢谢。但我看到了两个直接的问题。首先,您正在比较异常处理程序中的字符串,正如我所指出的,我没有收到任何异常。其次,我认为测试整个字符串是可疑的,这在未来很容易发生变化。至少,您应该对其进行解析以找到错误号,因为我相信 .NET 已经具有执行此操作的属性。 是的,可能,回复:特定字符串。鉴于我们正在部署到一个不太可能改变的已知服务器目标,我并不担心它是否会被我使用,但我同意如果其他客户端使用它,我会想要一个更好的解决方案。抱歉,我错过了您没有收到异常的地方……您的回复中是否返回了任何内容?还是只是空? 正如我的问题中提到的,我得到了一个空字符串。显然,如果导演存在,则返回相同的内容,但为空。【参考方案4】:

我使用以下内容来检查 ftp 连接凭据是否有效。您可以使用它来检查目录是否存在。如果 url、用户名和密码正确,则返回 true。

URL:您在此处指定您的目录路径。 用户:ftp用户名 密码:ftp密码


public static bool isValidConnection(string url, string user, string password, ref string errorMessage = "")

    try 
        FtpWebRequest request = (FtpWebRequest)WebRequest.Create(url);
        request.Method = WebRequestMethods.Ftp.ListDirectory;
        request.Credentials = new NetworkCredential(user, password);
        request.KeepAlive = false;
        request.UsePassive = true;
        FtpWebResponse response = (FtpWebResponse)request.GetResponse();
        response.Close();
     catch (WebException ex) 
        errorMessage = ex.Message;
        return false;
    
    return true;

【讨论】:

您正在使用WebRequestMethods.Ftp.ListDirectory。这正是我使用的。【参考方案5】:

一种方法是列出许多解决方案中存在的目录内容,但在我的情况下,我还必须读取数据内容,以便服务器检查目录。如果该目录不存在,则会抛出一个 webException,应将其解释为过滤意外错误。

这是我的解决方案:

  bool directoryExists(string path)
    

        bool? exists = null;


        FtpWebRequest request = (FtpWebRequest)WebRequest.Create(path);
        request.Method = WebRequestMethods.Ftp.ListDirectory;

        request.Credentials = new NetworkCredential("username", "*****");

        FtpWebResponse response = null;
        try
        
            response = (FtpWebResponse)request.GetResponse();

            using (StreamReader sr = new StreamReader(response.GetResponseStream()))
            
                string str = sr.ReadLine(); //Just needs to read one line to fire check on server
                sr.Close();
                return true;
                                                
        
        catch (WebException ex)  
        
            var r = (FtpWebResponse)ex.Response;
            if (r.StatusCode ==
                FtpStatusCode.ActionNotTakenFileUnavailable)
            
                //Does not exist
                return false;
            
            throw; //if error is not related to directory existence then the exception needs to be treated above.
        
        finally
        
            if (response != null)
                response.Close();
        
        return false;
    

我的目标 FTP 服务器我知道是 Windows 服务器,但我无权访问版本信息。

【讨论】:

以上是关于如何判断 FTP 目录是不是存在的主要内容,如果未能解决你的问题,请参考以下文章

FTP判断目录是否存在

FTP判断目录是否存在

cmd dos 检查远程FTP文件夹是不是存在

linux如何判断网络是百兆还是千兆

从FTP下载时如何检查文件是不是存在

java向SFTP服务器上传文件,如何判断服务器上的文件夹是不是存在?