如何检查FTP目录是否存在

35

寻找最佳方法通过FTP检查给定目录。

目前我的代码如下:

private bool FtpDirectoryExists(string directory, string username, string password)
{

    try
    {
        var request = (FtpWebRequest)WebRequest.Create(directory);
        request.Credentials = new NetworkCredential(username, password);
        request.Method = WebRequestMethods.Ftp.GetDateTimestamp;

        FtpWebResponse response = (FtpWebResponse)request.GetResponse();
    }
    catch (WebException ex)
    {
        FtpWebResponse response = (FtpWebResponse)ex.Response;
        if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
            return false;
        else
            return true;
    }
    return true;
}

无论该目录是否存在,此方法均返回false。 请问有人可以指点我吗。

11个回答

21

基本上,我这样捕获了创建目录时遇到的错误。

private bool CreateFTPDirectory(string directory) {

    try
    {
        //create the directory
        FtpWebRequest requestDir = (FtpWebRequest)FtpWebRequest.Create(new Uri(directory));
        requestDir.Method = WebRequestMethods.Ftp.MakeDirectory;
        requestDir.Credentials = new NetworkCredential("username", "password");
        requestDir.UsePassive = true;
        requestDir.UseBinary = true;
        requestDir.KeepAlive = false;
        FtpWebResponse response = (FtpWebResponse)requestDir.GetResponse();
        Stream ftpStream = response.GetResponseStream();

        ftpStream.Close();
        response.Close();

        return true;
    }
    catch (WebException ex)
    {
        FtpWebResponse response = (FtpWebResponse)ex.Response;
        if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
        {
            response.Close();
            return true;
        }
        else
        {
            response.Close();
            return false;
        }  
    }
}

14
这段代码不可靠:例如,如果您没有写入权限并且没有所需目录,此函数将返回真。 - Ivan Leonenko
2
还有一种选择是检查FtpWebResponse的StatusDescription属性。如果它包含“exists”(550目录已存在),则表示该目录已经存在。然而,我没有找到任何规范或保证,所有FTP服务器都必须返回该信息,这可能只适用于FileZilla。因此,在您特定的情况下进行测试,并决定是否要执行/冒险。 - erikbozic

17

完整解决方案现在是:

public bool DoesFtpDirectoryExist(string dirPath)
{
    try
    {
        FtpWebRequest request = (FtpWebRequest)WebRequest.Create(dirPath);  
        request.Method = WebRequestMethods.Ftp.ListDirectory;  
        FtpWebResponse response = (FtpWebResponse)request.GetResponse();
        return true;
     }
     catch(WebException ex)
     {
         return false;
     }
}

// Calling the method (note the forwardslash at the end of the path):
string ftpDirectory = "ftp://ftpserver.com/rootdir/test_if_exist_directory/";
bool dirExists = DoesFtpDirectoryExist(ftpDirectory);

最初我使用的是:

string ftpDirectory = "ftp://ftpserver.com/rootdir/test_if_exist_directory";
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpDirectory);  
request.Method = WebRequestMethods.Ftp.ListDirectory;  
FtpWebResponse response = (FtpWebResponse)request.GetResponse();

等待异常以防目录不存在。但是这种方法并没有抛出异常。

经过几次尝试,我将目录更改为:

ftp://ftpserver.com/rootdir/test_if_exist_directory

收件人:

ftp://ftpserver.com/rootdir/test_if_exist_directory/

现在代码对我起作用了。

我认为我们应该在FTP文件夹的URI末尾添加一个正斜杠(/)以使其正常工作。


一个 WebException 不能只表示缺少目录的错误,我建议你测试一下它的 StatusCode 是否等于 FtpStatusCode.ActionNotTakenFileUnavailable,如果不是就报告一个错误。 - Anton Shepelev

9

我假设您已经对FtpWebRequest有一定的了解,因为这是在.NET中访问FTP的常规方式。

您可以尝试列出目录并检查错误的StatusCode。

try 
{  
    FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftp.microsoft.com/12345");  
    request.Method = WebRequestMethods.Ftp.ListDirectory;  
    using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())  
    {  
        // Okay.  
    }  
}  
catch (WebException ex)  
{  
    if (ex.Response != null)  
    {  
        FtpWebResponse response = (FtpWebResponse)ex.Response;  
        if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)  
        {  
            // Directory not found.  
        }  
    }  
} 

1
我发现这是不可靠的。我有一个情况,在指定的目录不存在时没有抛出异常。 - Jonathan Wood
URL必须以斜杠结尾,代码才能可靠地工作:为什么FtpWebRequest返回这个现有目录的空流? - Martin Prikryl

7
我建议尝试以下方法:
  • 发送MLST <directory> FTP命令(在RFC3659中定义)并解析其输出。它应该返回有效的目录详细信息,以验证现有目录。

  • 如果MLST命令不可用,则尝试使用CWD命令将工作目录更改为被测试的目录。别忘了在更改到被测试的目录之前确定当前路径(PWD命令),以便能够返回。

  • 在某些服务器上,可以使用MDTM和SIZE命令的组合来实现类似的目的,但行为相当复杂,超出了本文档的范围。

这基本上就是我们Rebex FTP组件当前版本中的DirectoryExists方法所做的事情。以下代码展示了如何使用它:

string path = "/path/to/directory";

Rebex.Net.Ftp ftp = new Rebex.Net.Ftp();
ftp.Connect("hostname");
ftp.Login("username","password");

Console.WriteLine(
  "Directory '{0}' exists: {1}", 
  path, 
  ftp.DirectoryExists(path)
);

ftp.Disconnect();

3
尽管其他答案提供了代码,但它们基本上是创建一个新目录来查看是否会出现错误。更好的方法是直接发出FTP的“CWD”命令,如果目录不存在,服务器将发出5xx回复代码。 - timbo

4

使用这段代码可能是你的答案...

 public bool FtpDirectoryExists(string directoryPath, string ftpUser, string ftpPassword)
        {
            bool IsExists = true;
            try
            {
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(directoryPath);
                request.Credentials = new NetworkCredential(ftpUser, ftpPassword);
                request.Method = WebRequestMethods.Ftp.PrintWorkingDirectory;

                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                IsExists = false;
            }
            return IsExists;
        }

我将该方法称为:

bool result =    FtpActions.Default.FtpDirectoryExists( @"ftp://mydomain.com/abcdir", txtUsername.Text, txtPassword.Text);

为什么要使用另一个库 - 创建自己的逻辑。

13
这将仅返回当前工作目录(CWD)。无论您附加到主机地址的内容是什么(例如:ftp://mydomain.com),它总是返回当前目录。换句话说,IsExists永远不会是除true以外的任何其他值。如果我只做这件事(如上所述),那么在我的服务器上,它只会显示“257 '/' is current directory。”而不是像每个人都期望的那样显示“257 '/abcdir/' is current directory.” - Arvo Bowen

2
我尝试了各种方法来获得一个可靠的检查,但是无论是 WebRequestMethods.Ftp.PrintWorkingDirectory 还是 WebRequestMethods.Ftp.ListDirectory 方法都不能正确工作。当检查不存在于服务器上的 ftp://<website>/Logs 时,它们会失败,但是它们说存在。
因此,我想到的方法是尝试上传到文件夹中。然而,一个“陷阱”是路径格式,您可以在这个线程中阅读到关于它的信息:Uploading to Linux 这是一个代码片段:
private bool DirectoryExists(string d) 
{ 
    bool exists = true; 
    try 
    { 
        string file = "directoryexists.test"; 
        string path = url + homepath + d + "/" + file;
        //eg ftp://website//home/directory1/directoryexists.test
        //Note the double space before the home is not a mistake

        //Try to save to the directory 
        req = (FtpWebRequest)WebRequest.Create(path); 
        req.ConnectionGroupName = "conngroup1"; 
        req.Method = WebRequestMethods.Ftp.UploadFile; 
        if (nc != null) req.Credentials = nc; 
        if (cbSSL.Checked) req.EnableSsl = true; 
        req.Timeout = 10000; 

        byte[] fileContents = System.Text.Encoding.Unicode.GetBytes("SAFE TO DELETE"); 
        req.ContentLength = fileContents.Length; 

        Stream s = req.GetRequestStream(); 
        s.Write(fileContents, 0, fileContents.Length); 
        s.Close(); 

        //Delete file if successful 
        req = (FtpWebRequest)WebRequest.Create(path); 
        req.ConnectionGroupName = "conngroup1"; 
        req.Method = WebRequestMethods.Ftp.DeleteFile; 
        if (nc != null) req.Credentials = nc; 
        if (cbSSL.Checked) req.EnableSsl = true; 
        req.Timeout = 10000; 

        res = (FtpWebResponse)req.GetResponse(); 
        res.Close(); 
    } 
    catch (WebException ex) 
    { 
        exists = false; 
    } 
    return exists; 
} 

0

我无法让@BillyLogans的建议起作用...

我发现问题在于默认FTP目录是/home/usr/fred

当我使用:

String directory = "ftp://some.domain.com/mydirectory"
FtpWebRequest requestDir = (FtpWebRequest)FtpWebRequest.Create(new Uri(directory));

我发现这个会被转换成

"ftp:/some.domain.com/home/usr/fred/mydirectory"

为了停止这个更改,请将目录Uri更改为:

String directory = "ftp://some.domain.com//mydirectory"

然后这个开始工作。



0
转到父目录,执行“ls”命令并解析结果。

但是,如果父目录不存在,则会返回错误状态550。 - Anthony Brenelière

-1

这是我最好的表现。从父目录获取列表,并检查父目录是否有正确的子文件名。

public void TryConnectFtp(string ftpPath)
        {
            string[] splited = ftpPath.Split('/');
            StringBuilder stb = new StringBuilder();
            for (int i = 0; i < splited.Length - 1; i++)
            {
                stb.Append(splited[i] +'/');
            }
            string parent = stb.ToString();
            string child = splited.Last();

            FtpWebRequest testConnect = (FtpWebRequest)WebRequest.Create(parent);
            testConnect.Method = WebRequestMethods.Ftp.ListDirectory;
            testConnect.Credentials = credentials;
            using (FtpWebResponse resFtp = (FtpWebResponse)testConnect.GetResponse())
            {
                StreamReader reader = new StreamReader(resFtp.GetResponseStream());
                string result = reader.ReadToEnd();
                if (!result.Contains(child) ) throw new Exception("@@@");

                resFtp.Close();
            }
        }

-3
唯一对我有效的方法是通过尝试创建目录/路径(如果已存在,则会引发异常),然后在此后删除它。否则,使用异常来设置标志,表示目录/路径已存在。我对VB.NET还很陌生,我相信有一种更好的编码方式 - 但无论如何,这是我的代码:
        Public Function DirectoryExists(directory As String) As Boolean
        ' Reversed Logic to check if a Directory exists on FTP-Server by creating the Directory/Path
        ' which will throw an exception if the Directory already exists. Otherwise create and delete the Directory

        ' Adjust Paths
        Dim path As String
        If directory.Contains("/") Then
            path = AdjustDir(directory)     'ensure that path starts with a slash
        Else
            path = directory
        End If

        ' Set URI (formatted as ftp://host.xxx/path)

        Dim URI As String = Me.Hostname & path

        Dim response As FtpWebResponse

        Dim DirExists As Boolean = False
        Try
            Dim request As FtpWebRequest = DirectCast(WebRequest.Create(URI), FtpWebRequest)
            request.Credentials = Me.GetCredentials
            'Create Directory - if it exists WebException will be thrown
            request.Method = WebRequestMethods.Ftp.MakeDirectory

            'Delete Directory again - if above request did not throw an exception
            response = DirectCast(request.GetResponse(), FtpWebResponse)
            request = DirectCast(WebRequest.Create(URI), FtpWebRequest)
            request.Credentials = Me.GetCredentials
            request.Method = WebRequestMethods.Ftp.RemoveDirectory
            response = DirectCast(request.GetResponse(), FtpWebResponse)
            DirExists = False

        Catch ex As WebException
            DirExists = True
        End Try
        Return DirExists

    End Function

我使用的方法是 WebRequestMethods.Ftp.MakeDirectory 和 WebRequestMethods.Ftp.RemoveDirectory。其他所有解决方案对我都不起作用。

希望能对你有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接