C#上传文件到Linux的FTP

3
我正在尝试检查FTP服务器上的一个目录是否存在。在您说“使用ListDirectory”或“使用PrintWorkingDirectory”之前,它们并不总是有效的;例如,我测试了ftp://webserver/Logs是否存在,但它们都告诉我它存在,实际上并不存在。因此,我通过将文件上传到该目录并在成功时检查来判断该目录是否存在。
问题是,下面的方法不能在GoDaddy基于CentOS的服务器上工作,该服务器运行vsFTPd 2.0.7.2。它在IIS7.5上的Microsoft FTP服务器上运行良好。
因此,我使用Wireshark监视了流量,并使用Filezilla查看它所做的以使其正常工作。唯一的区别是Filezilla正在更改工作目录,而我正在尝试在路径之前上传文件。
我有一种感觉,这与上传到服务器的路径及其在Linux上的解释有关,因为名称可能有点奇怪... :-D 任何想法都受到热烈欢迎。 应用程序代码
private bool DirectoryExists(string d)
{
    bool exists = true;
    try
    {
        string file = "directoryexists.test";
        string path = url + homepath + d + "/" + file;

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

通过Wireshark查看Filezilla日志

Response: 230 Login successful.
Request: CWD /Home/test1
Response: 250 Directory successfully changed.
Request: TYPE I
Response: 200 Switching to Binary mode.
Request: PASV
Response: 227 Entering Passive Mode (216,69,186,142,71,209)
Request: LIST
Response: 150 Here comes the directory listing.
FTP Data: 78 bytes
Response: 226 Directory send OK.
Request: PASV
Response: 227 Entering Passive Mode (216,69,186,142,177,1)
Request: STOR directoryexists.txt
Response: 150 Ok to send data.
Response: 226 File receive OK.

通过Wireshark查看应用程序日志

Response: 230 Login successful.
Request: OPTS utf8 on
Response: 501 Option not understood.
Request: PWD
Response: 257 "/Home/"
Request: PWD
Response: 257 "/Home/"
Request: TYPE I
Response: 200 Switching to Binary mode.
Request: PASV
Response: 227 Entering Passive Mode (216,69,186,142,217,87)
Request: STOR test1/directoryexists.txt
Response: 553 Could not create file.

它会创建文件夹(如果它们不存在)。
Response: 230 Login successful.
Request: PWD
Response: 257 "/Home/"
Request: PWD
Response: 257 "/Home/"
Request: TYPE I
Response: 200 Switching to Binary mode.
Request: PASV
Response: 227 Entering Passive Mode (216,69,186,142,220,60)
Request: STOR Logs/directoryexists.txt
Response: 553 Could not create file.
Request: PWD
Response: 257 "/Home/"
Request: MKD Logs
Response: 257 Create folder operation successful.
Request: TYPE I
Response: 200 Switching to Binary mode.
Request: PASV
Response: 227 Entering Passive Mode (216,69,186,142,255,245)
Request: STOR Logs/LogFiles/directoryexists.txt
Response: 553 Could not create file.
Request: PWD
Response: 257 "/Home/"
Request: MKD Logs/LogFiles
Response: 257 Create folder operation successful.

通常,553错误与权限有关。我看到Wireshark捕获了STOR test1/directoryexists.txt。在FTP服务器上,您是否无法在/Home/下创建另一个嵌套目录?一些托管提供商限制了您可以嵌套目录的深度,因此您可能不被允许将文件夹放置得如此深或者甚至更深。根据Wireshark的信息,您当前位于/Home/,所以您应该只需执行STOR directoryexists.txt即可。 - Bryan Crosby
@Bryan: 感谢你的想法,但我刚刚测试了一下,而且运行良好。响应:257 "/Home/A/B/C/" - Christian
你尝试过将 req.Method 设置为 WebRequestMethods.Ftp.MakeDirectory,创建目录,然后再尝试上传文件吗? - Bryan Crosby
@Bryan:在下面回答了自己的问题。感谢您的建议。 - Christian
1个回答

4

Linux又来捣乱了...

解决方案是在路径名中设置双斜杠,这样当它进行STOR操作时,就有一个前导斜杠...像这样:

string url = "ftp://website/";
string homepath = "/Home/";
string d = "test1";
string file = "directoryexists.test";

string path = url + homepath + d + "/" + file;

因此,完整路径将看起来像 ftp://website//Home/test1/directoryexists.test

req = (FtpWebRequest)WebRequest.Create("ftp://website//Home/test1/directoryexists.test"); 

那样,"STOR" 命令将会变成:
STOR /Home/test1/directoryexists.test

您可以从StatusDescription中获取主目录路径。
req = (FtpWebRequest)WebRequest.Create(url);
req.Method = WebRequestMethods.Ftp.PrintWorkingDirectory;
if (nc != null) req.Credentials = nc;
if (cbSSL.Checked) req.EnableSsl = true;
req.Timeout = 10000;
res = (FtpWebResponse)req.GetResponse();

System.Text.RegularExpressions.Regex regexp = new System.Text.RegularExpressions.Regex("\\s\"([^\"]*)\"\\s");
homepath = regexp.Match(res.StatusDescription).Groups[1].Value;

res.Close();

Linux不是FTP服务器。但很高兴您找到了解决方案。 - Merlyn Morgan-Graham
感谢明显的提示,Merlyn ;) - Christian
我刚遇到同样的问题,用双斜杠将FTP URL与文件路径分开也对我有用。谢谢! - MikeWyatt

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