如何确定FTP目录是否存在

时间:2014-07-15 15:00:26

标签: c# .net ftp webrequest ftpwebrequest

我编写了以下代码来检测目录是否存在。 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”

     

的ContentLength = -1

     

ExitMessage =“221 Goodbye。\ r \ n”

     

的StatusCode = ClosingData

     

StatusDescription =“226传输完成。\ r \ n”

     

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

更新

最终,我发现大多数人一直在推荐我最初做的变化。这对Hans Passant的建议很重要,因为服务器存在问题。我试图让他们看看这个,但他们似乎对整个讨论感到困惑。我知道他们正在使用微软服务器,我很怀疑我能从他们那里获得解决方案。

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

5 个答案:

答案 0 :(得分:6)

当您要求提供不存在的目录/文件时,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/pub/data/bloat-reports2/ 返回false

有一个很大但有关的尾随/路径。

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

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

ftp://ftp.mozilla.org/pub/mozilla.org/返回false然后是真的?????

此行为与您描述的内容类似。您可以在浏览器上轻松地重现它。我建议你用你自己的路径做同样的事情并检查目录的内容。如果你有空文件,删除它们或用空格替换它们的内容,最后检查你的代码,以确保你不会创建新文件或重新创建零字节长度。

我希望这会有所帮助。

<强>更新

没有新闻,坏消息!我假设上述任何内容都没有帮助你。也许通过在你的道路上上升一级将解决问题。我们的想法是获取父目录的列表并检查它的子名称。如果父路径有效,则应始终返回非空字符串。代码如下:

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;
    }
}

正如您所看到的,无需担心拖尾斜杠。

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

答案 1 :(得分:0)

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

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

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

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

答案 2 :(得分:0)

我有类似的代码,可以通过FTP将项目部署到IIS 6 / Windows 2003 Server。这工作正常,直到我指向IIS7 / Windows 2008服务器。我开始看到你做的完全相同的行为。我调试它并最终将我的代码更改为以下内容。这是我的代码的直接片段。如果你愿意,我可以从它调用的方法中包含源代码,但我认为你理解这些操作。

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

答案 3 :(得分:0)

我使用以下内容检查ftp连接凭据是否有效。您可以使用相同的方法来检查目录是否存在。如果url,username和password正确,则返回true。

URL:您在此处指定目录路径。 user: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;
}

答案 4 :(得分:0)

一种方法是列出许多解决方案中存在的目录内容,但在我的情况下,我还必须读取数据内容,以便服务器检查目录。如果目录不存在,则抛出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服务器,但我无法访问版本信息。