如何确定FTP目录是否存在?

时间:2022-03-24 03:46:13

I wrote the following code to detect if a directory exists. The DirectoryExists method accepts either a fully qualified or relative path.

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

Note: _host.GetUrl(filename) returns the fully qualified path of the specified directory or filename. In my case, this is ftp://www.mydomain.com/Articles/controls/precisely-defining-kilobytes-megabytes-and-gigabytes.

注意:_host.GetUrl(文件名)返回指定目录或文件名的完全限定路径。在我的例子中,这是ftp://www.dommyain.com/articles/controls/precision - defin- defined -kilo - mb - mb -and- gb。

This code has worked for many months. But all of a sudden it stopped working. Now, there is no exception raised in DirectoryExists when the directory does not exist. sr.ReadToEnd() simply returns an empty string.

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

I posted a similar question and it was suggested that I should always append / to the end of my path. I tried that, and thought I got an exception once, but it's not raising an exception now.

我贴出了一个类似的问题,有人建议我应该把它加到我的路的尽头。我试过了,认为我有过一次例外,但现在还没有出现例外。

I don't know if the behavior changed on the FTP server I'm communicating with or what. Again, this worked fine when I wrote it and now it doesn't.

我不知道我正在与之通信的FTP服务器上的行为是否发生了改变。再一次,我写的时候效果很好,但现在不行。

How can I determine whether or not an FTP directory exists?

如何确定FTP目录是否存在?

EDIT:

编辑:

Inspecting the response after calling ReadToEnd(), I see:

在调用ReadToEnd()之后检查响应,我看到:

BannerMessage="220 Microsoft FTP Service\r\n"

BannerMessage = " 220微软FTP服务\ r \ n”

ContentLength=-1

ContentLength = 1

ExitMessage="221 Goodbye.\r\n"

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

StatusCode=ClosingData

StatusCode = ClosingData

StatusDescription="226 Transfer complete.\r\n"

StatusDescription = " 226转移完成。\ r \ n”

WelcomeMessage="230 User logged in.\r\n"

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

UPDATE:

更新:

Ultimately, I see that most people have been recommending variations of what I was doing originally. This has lent weight to Hans Passant's suggestion that the issue lies with the server. I am attempting to get them to look at this but they seem a little baffled by the entire discussion. I know they are using a Microsoft server, and I'm skeptical I will be able to get a resolution from them.

最后,我发现大多数人都在推荐我最初所做的事情的变体。这支持了Hans Passant的观点,即问题在于服务器。我想让他们看看这个,但他们似乎对整个讨论有点困惑。我知道他们正在使用微软的服务器,我怀疑我能否从他们那里得到解决方案。

If all else fails, I think the answer is to do a listing of the parent directory, which does require some extra work to handle cases such as when the directory in question is the root, and also cases when the parent doesn't exist.

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

5 个解决方案

#1


6  

FTP servers reply with a 550 message when you ask for a non existing directory/file. This 550 is translated to an exception in .NET.

当您请求一个不存在的目录/文件时,FTP服务器会回复550个消息。这个550被翻译成。net中的一个异常。

Regarding the code you presented I don't see the reason to use a StreamReader in production. A simple modification is the following:

关于您提供的代码,我不认为有理由在生产中使用StreamReader。一项简单的修改如下:

public bool DirectoryExists(string directory)
{
  try
  {
    FtpWebRequest request = GetRequest(directory);
    request.Method = WebRequestMethods.Ftp.ListDirectory;
    return request.GetResponse() != null;
  }
  catch
  {
    return false;
  }
}

I kept the exception handling as is (missing) but I suggest you to work on it as there are many and different cases to catch that are not related to ftp responses.

我保留了异常处理(缺少),但是我建议您处理它,因为有许多不同的情况需要捕获,而这些情况与ftp响应无关。

request.GetResponse() will generate an exception if the directory does not exist.

如果目录不存在,request.GetResponse()将生成一个异常。

I tried it with the following paths for true returns:

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

The last one is an existing but empty directory

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

ftp://ftp.mozilla.org/pub/data/bloat-reports2/ returns false

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

There is a big but regarding trailing / in paths.

有一个很大的,但是关于后面/在路径。

mozilla.org is a zero byte length file under pub directory

在pub目录下,mozilla.org是一个0字节长度的文件。

ftp://ftp.mozilla.org/pub/mozilla.org returns true

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

ftp://ftp.mozilla.org/pub/mozilla.org/ returned false and then true ?????

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

This behavior looks like with what you described. You can easily reproduce it on a browser. I suggest you to do the same with your own paths and check the contents of the directories. In case you do have empty files, remove them or replace their contents with a space, and finally check your code to ensure that you will not create new files or recreate them with zero byte length.

这种行为与您描述的类似。您可以在浏览器中轻松复制它。我建议您对自己的路径进行相同的操作,并检查目录的内容。如果您有空文件,删除它们或用空格替换它们的内容,最后检查您的代码,以确保您不会创建新文件或以零字节长度重新创建它们。

I hope that this helps.

我希望这能有所帮助。

UPDATE

更新

No news, bad news! I assume that nothing of the above helped you. Maybe by going one level up in your path will solve the problem. The idea is to get a list of the parent directory and check it for the child name. If the parent path is valid it should always return non empty string. The code is the following:

没有消息,坏消息!我想以上这些对你毫无帮助。也许在你的道路上走一层就能解决问题。其思想是获取父目录的列表并检查它的子目录名。如果父路径是有效的,它应该总是返回非空字符串。守则如下:

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

As you can see there is no need to worry about trailing slashes.

正如您所看到的,没有必要担心拖尾斜杠。

Warning: The code will not cover the case of a subdirectory and a filename with same names under the same path.

警告:该代码将不涉及子目录和文件名在相同路径下具有相同名称的情况。

#2


0  

This might happen because FTP server software installed on your server.

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

Otherwise, you may want to take a look at response.StatusCode to see if there is any hints.

否则,您可能需要查看一下响应。查看是否有任何提示。

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

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

Finally, if all of that doesn't work, try to write a dumb text file on that un-existed directory.

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

#3


0  

I had similar code that would deploy items via FTP to an IIS 6/Windows 2003 Server. This worked fine until I pointed it at an IIS7/Windows 2008 server. I started seeing the exact same behavior you did. I debugged it and ultimately changed my code to the following. This is a direct snippet from my code. I can include the source from the methods it calls if you like, but I think you understand those operations.

我有类似的代码,可以通过FTP将项目部署到IIS 6/Windows 2003服务器上。直到我在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;
    }
}

relevant section of GetFtpListing

相关部门的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));
    }

#4


0  

I use the below to check if a ftp connection credentials are valid. You may use the same to check if directory exists. Returns true if url, username, and password are correct.

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

URL: you specify your directory path in here. user: ftp username password: ftp password

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

#5


0  

One way is to list the directory content as present in many solutions, but in my case i also have to read data content so the server checks the directory. If the directory is not present, an webException is throw that should be interpreted to filter from unexpected errors.

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

Here is my solution:

这是我的解决方案:

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

The FTP server i am targeting i know to be a windows server but i don't have access to the version information.

我瞄准的FTP服务器我知道是windows服务器,但是我不能访问版本信息。

#1


6  

FTP servers reply with a 550 message when you ask for a non existing directory/file. This 550 is translated to an exception in .NET.

当您请求一个不存在的目录/文件时,FTP服务器会回复550个消息。这个550被翻译成。net中的一个异常。

Regarding the code you presented I don't see the reason to use a StreamReader in production. A simple modification is the following:

关于您提供的代码,我不认为有理由在生产中使用StreamReader。一项简单的修改如下:

public bool DirectoryExists(string directory)
{
  try
  {
    FtpWebRequest request = GetRequest(directory);
    request.Method = WebRequestMethods.Ftp.ListDirectory;
    return request.GetResponse() != null;
  }
  catch
  {
    return false;
  }
}

I kept the exception handling as is (missing) but I suggest you to work on it as there are many and different cases to catch that are not related to ftp responses.

我保留了异常处理(缺少),但是我建议您处理它,因为有许多不同的情况需要捕获,而这些情况与ftp响应无关。

request.GetResponse() will generate an exception if the directory does not exist.

如果目录不存在,request.GetResponse()将生成一个异常。

I tried it with the following paths for true returns:

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

The last one is an existing but empty directory

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

ftp://ftp.mozilla.org/pub/data/bloat-reports2/ returns false

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

There is a big but regarding trailing / in paths.

有一个很大的,但是关于后面/在路径。

mozilla.org is a zero byte length file under pub directory

在pub目录下,mozilla.org是一个0字节长度的文件。

ftp://ftp.mozilla.org/pub/mozilla.org returns true

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

ftp://ftp.mozilla.org/pub/mozilla.org/ returned false and then true ?????

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

This behavior looks like with what you described. You can easily reproduce it on a browser. I suggest you to do the same with your own paths and check the contents of the directories. In case you do have empty files, remove them or replace their contents with a space, and finally check your code to ensure that you will not create new files or recreate them with zero byte length.

这种行为与您描述的类似。您可以在浏览器中轻松复制它。我建议您对自己的路径进行相同的操作,并检查目录的内容。如果您有空文件,删除它们或用空格替换它们的内容,最后检查您的代码,以确保您不会创建新文件或以零字节长度重新创建它们。

I hope that this helps.

我希望这能有所帮助。

UPDATE

更新

No news, bad news! I assume that nothing of the above helped you. Maybe by going one level up in your path will solve the problem. The idea is to get a list of the parent directory and check it for the child name. If the parent path is valid it should always return non empty string. The code is the following:

没有消息,坏消息!我想以上这些对你毫无帮助。也许在你的道路上走一层就能解决问题。其思想是获取父目录的列表并检查它的子目录名。如果父路径是有效的,它应该总是返回非空字符串。守则如下:

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

As you can see there is no need to worry about trailing slashes.

正如您所看到的,没有必要担心拖尾斜杠。

Warning: The code will not cover the case of a subdirectory and a filename with same names under the same path.

警告:该代码将不涉及子目录和文件名在相同路径下具有相同名称的情况。

#2


0  

This might happen because FTP server software installed on your server.

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

Otherwise, you may want to take a look at response.StatusCode to see if there is any hints.

否则,您可能需要查看一下响应。查看是否有任何提示。

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

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

Finally, if all of that doesn't work, try to write a dumb text file on that un-existed directory.

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

#3


0  

I had similar code that would deploy items via FTP to an IIS 6/Windows 2003 Server. This worked fine until I pointed it at an IIS7/Windows 2008 server. I started seeing the exact same behavior you did. I debugged it and ultimately changed my code to the following. This is a direct snippet from my code. I can include the source from the methods it calls if you like, but I think you understand those operations.

我有类似的代码,可以通过FTP将项目部署到IIS 6/Windows 2003服务器上。直到我在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;
    }
}

relevant section of GetFtpListing

相关部门的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));
    }

#4


0  

I use the below to check if a ftp connection credentials are valid. You may use the same to check if directory exists. Returns true if url, username, and password are correct.

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

URL: you specify your directory path in here. user: ftp username password: ftp password

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

#5


0  

One way is to list the directory content as present in many solutions, but in my case i also have to read data content so the server checks the directory. If the directory is not present, an webException is throw that should be interpreted to filter from unexpected errors.

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

Here is my solution:

这是我的解决方案:

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

The FTP server i am targeting i know to be a windows server but i don't have access to the version information.

我瞄准的FTP服务器我知道是windows服务器,但是我不能访问版本信息。