当当前用户目录与 root 不同时,无法使用 ftp 方法重命名文件

发布于 2024-09-05 12:25:43 字数 5337 浏览 2 评论 0原文

备注:由于垃圾邮件预防机制,我被迫将 Uris 的开头从 ftp:// 替换为 ftp。

我有以下问题。我必须使用 C# ftp 方法上传文件,然后重命名它。容易,对吧? :)

好吧,假设我的 ftp 主机是这样的:

ftp.contoso.com

登录后,当前目录设置为:

用户/名称

所以,我想要实现的是登录,将文件作为 file.ext.tmp 上传到当前目录,上传成功后,将文件重命名为 file.ext

正如我猜测的那样,整个困难是,正确设置 FtpWebRequest 的请求 Uri。

MSDN 指出:

URI 可以是相对的或绝对的。如果 URI 的格式为“ftp://contoso.com/%2fpath”(%2f 是转义了 '/'),​​则 URI 是绝对的,当前目录是 /path。但是,如果 URI 的格式为“ftp://contoso.com/path”,则首先将 . NET Framework 登录到 FTP 服务器(使用 Credentials 属性设置的用户名和密码),然后将当前目录设置为 UserLoginDirectory/path。

好的,我使用以下 URI 上传文件:

ftp.contoso.com/file.ext.tmp

太好了,文件到达了我想要的位置:在目录“users/name”中

现在,我想重命名该文件,因此我使用以下 Uri 创建 Web 请求:

ftp.contoso.com/file.ext.tmp

并将参数重命名为:

文件.ext

,这给了我 550 错误:找不到文件,没有权限等。

我在 Microsoft 网络监视器中跟踪了这个,它给了我:

命令:RNFR,重命名自
命令参数:/file.ext.tmp
Ftp:响应端口 53724,“550 文件 /file.ext.tmp 未找到”

就好像它正在根目录中查找文件 - 而不是在当前目录中一样。

我使用 Total Commander 手动重命名了该文件,唯一的区别是 CommandParameter 没有第一个斜杠:

命令参数:file.ext.tmp

我可以通过提供以下绝对 URI 成功重命名该文件:

ftp.contoso.com/%2fusers/%2fname/file.ext.tmp

但我不喜欢这种方法,因为我必须知道当前用户目录的名称。它可能可以通过使用 WebRequestMethods.Ftp.PrintWorkingDirectory 来完成,但它增加了额外的复杂性(调用此方法来检索目录名称,然后组合路径以形成正确的 URI)。

我不明白的是为什么 URI ftp.contoso.com/file.ext.tmp 适合上传而不适合重命名?我在这里错过了什么吗?

该项目设置为 .NET 4.0,在 Visual Studio 2010 中编码。

编辑

好的,我放置代码片段。

请注意,应填写 ftp 主机、用户名和密码。为了使该示例正常工作(即产生错误),用户目录必须与 root 不同(“pwd”命令应返回与“/”不同的内容)

class Program
{
    private const string fileName = "test.ext";
    private const string tempFileName = fileName + ".tmp";
    private const string ftpHost = "127.0.0.1";
    private const string ftpUserName = "anonymous";
    private const string ftpPassword = "";
    private const int bufferSize = 524288;

    static void Main(string[] args)
    {
        try
        {
            string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fileName);

            if (!File.Exists(path))
                File.WriteAllText(path, "FTP RENAME SAMPLE");

            string requestUri = "ftp://" + ftpHost + "/" + tempFileName;

            //upload

            FtpWebRequest uploadRequest = (FtpWebRequest)WebRequest.Create(requestUri);
            uploadRequest.UseBinary = true;
            uploadRequest.UsePassive = true;
            uploadRequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
            uploadRequest.KeepAlive = true;
            uploadRequest.Method = WebRequestMethods.Ftp.UploadFile;

            Stream requestStream = null;
            FileStream localFileStream = null;


            localFileStream = File.OpenRead(path);
            requestStream = uploadRequest.GetRequestStream();
            byte[] buffer = new byte[bufferSize];

            int readCount = localFileStream.Read(buffer, 0, bufferSize);
            long bytesSentCounter = 0;

            while (readCount > 0)
            {
                requestStream.Write(buffer, 0, readCount);
                bytesSentCounter += readCount;
                readCount = localFileStream.Read(buffer, 0, bufferSize);
                System.Threading.Thread.Sleep(100);
            }

            localFileStream.Close();
            requestStream.Close();

            FtpWebResponse response = (FtpWebResponse)uploadRequest.GetResponse();
            FtpStatusCode code = response.StatusCode;
            string description = response.StatusDescription;
            response.Close();

            if (code == FtpStatusCode.ClosingData)
                Console.WriteLine("File uploaded successfully");

            //rename

            FtpWebRequest renameRequest = (FtpWebRequest)WebRequest.Create(requestUri);
            renameRequest.UseBinary = true;
            renameRequest.UsePassive = true;
            renameRequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
            renameRequest.KeepAlive = true;
            renameRequest.Method = WebRequestMethods.Ftp.Rename;
            renameRequest.RenameTo = fileName;

            try
            {

                FtpWebResponse renameResponse = (FtpWebResponse)renameRequest.GetResponse();

                Console.WriteLine("Rename OK, status code: {0}, rename status description: {1}", response.StatusCode, response.StatusDescription);

                renameResponse.Close();
            }
            catch (WebException ex)
            {
                Console.WriteLine("Rename failed, status code: {0}, rename status description: {1}", ((FtpWebResponse)ex.Response).StatusCode, 
                    ((FtpWebResponse)ex.Response).StatusDescription);
            }

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
        finally
        {
            Console.ReadKey();
        }
    }
}

Remark: due to spam prevention mechanizm I was forced to replace the beginning of the Uris from ftp:// to ftp.

I've got following problem. I have to upload file with C# ftp method and afterwards rename it. Easy, right? :)

Ok, let's say my ftp host is like this:

ftp.contoso.com

and after logging in, current directory is set to:

users/name

So, what I'm trying to achieve is to log in, upload file to current directory as file.ext.tmp and after upload is successful, rename the file to file.ext

The whole difficulty is, as I guess, to properly set the request Uri for FtpWebRequest.

MSDN states:

The URI may be relative or absolute. If the URI is of the form "ftp://contoso.com/%2fpath" (%2f is an escaped '/'), then the URI is absolute, and the current directory is /path. If, however, the URI is of the form "ftp://contoso.com/path", first the .NET Framework logs into the FTP server (using the user name and password set by the Credentials property), then the current directory is set to UserLoginDirectory/path.

Ok, so I upload file with the following URI:

ftp.contoso.com/file.ext.tmp

Great, the file lands where I wanted it to be: in directory "users/name"

Now, I want to rename the file, so I create web request with following Uri:

ftp.contoso.com/file.ext.tmp

and specify rename to parameter as:

file.ext

and this gives me 550 error: file not found, no permissions, etc.

I traced this in Microsoft Network Monitor and it gave me:

Command: RNFR, Rename from
CommandParameter: /file.ext.tmp
Ftp: Response to Port 53724, '550 File /file.ext.tmp not found'

as if it was looking for the file in the root directory - not in the current directory.

I renamed the file manually using Total Commander and the only difference was that CommandParameter was without the first slash:

CommandParameter: file.ext.tmp

I'm able to successfully rename the file by supplying following absolute URI:

ftp.contoso.com/%2fusers/%2fname/file.ext.tmp

but I don't like this approach, since I would have to know the name of current user's directory. It can probably be done by using WebRequestMethods.Ftp.PrintWorkingDirectory, but it adds extra complexity (calling this method to retrieve directory name, then combining the paths to form proper URI).

What I don't understand is why the URI ftp.contoso.com/file.ext.tmp is good for upload and not for rename? Am I missing something here?

The project is set to .NET 4.0, coded in Visual Studio 2010.

Edit

Ok, I place code snippet.

Please note that ftp host, username and password should be filled out. For this sample to work - that is, produce an error - user directory must be different from root ("pwd"-command should return something different than "/")

class Program
{
    private const string fileName = "test.ext";
    private const string tempFileName = fileName + ".tmp";
    private const string ftpHost = "127.0.0.1";
    private const string ftpUserName = "anonymous";
    private const string ftpPassword = "";
    private const int bufferSize = 524288;

    static void Main(string[] args)
    {
        try
        {
            string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fileName);

            if (!File.Exists(path))
                File.WriteAllText(path, "FTP RENAME SAMPLE");

            string requestUri = "ftp://" + ftpHost + "/" + tempFileName;

            //upload

            FtpWebRequest uploadRequest = (FtpWebRequest)WebRequest.Create(requestUri);
            uploadRequest.UseBinary = true;
            uploadRequest.UsePassive = true;
            uploadRequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
            uploadRequest.KeepAlive = true;
            uploadRequest.Method = WebRequestMethods.Ftp.UploadFile;

            Stream requestStream = null;
            FileStream localFileStream = null;


            localFileStream = File.OpenRead(path);
            requestStream = uploadRequest.GetRequestStream();
            byte[] buffer = new byte[bufferSize];

            int readCount = localFileStream.Read(buffer, 0, bufferSize);
            long bytesSentCounter = 0;

            while (readCount > 0)
            {
                requestStream.Write(buffer, 0, readCount);
                bytesSentCounter += readCount;
                readCount = localFileStream.Read(buffer, 0, bufferSize);
                System.Threading.Thread.Sleep(100);
            }

            localFileStream.Close();
            requestStream.Close();

            FtpWebResponse response = (FtpWebResponse)uploadRequest.GetResponse();
            FtpStatusCode code = response.StatusCode;
            string description = response.StatusDescription;
            response.Close();

            if (code == FtpStatusCode.ClosingData)
                Console.WriteLine("File uploaded successfully");

            //rename

            FtpWebRequest renameRequest = (FtpWebRequest)WebRequest.Create(requestUri);
            renameRequest.UseBinary = true;
            renameRequest.UsePassive = true;
            renameRequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
            renameRequest.KeepAlive = true;
            renameRequest.Method = WebRequestMethods.Ftp.Rename;
            renameRequest.RenameTo = fileName;

            try
            {

                FtpWebResponse renameResponse = (FtpWebResponse)renameRequest.GetResponse();

                Console.WriteLine("Rename OK, status code: {0}, rename status description: {1}", response.StatusCode, response.StatusDescription);

                renameResponse.Close();
            }
            catch (WebException ex)
            {
                Console.WriteLine("Rename failed, status code: {0}, rename status description: {1}", ((FtpWebResponse)ex.Response).StatusCode, 
                    ((FtpWebResponse)ex.Response).StatusDescription);
            }

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
        finally
        {
            Console.ReadKey();
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

最近可好 2024-09-12 12:25:43

我遇到过类似的问题。问题在于 FtpWebRequest(错误地)在重命名请求前添加“/”,从该日志(上传和重命名)中可以看出:

URL: 
  http://127.0.0.1/Test.txt
FTP log:
  STOR Test.txt.part
  RNFR /Test.txt.part
  RNTO /Test.txt

请注意,仅当您上传到根目录时才会出现此问题。如果您将 URL 更改为 http://127.0.0.1/path/Test.txt,那么一切都会正常工作。

我对此问题的解决方案是使用 %2E(点)作为路径:

URL:
  http://127.0.0.1/%2E/Test.txt
FTP log:
 STOR ./Test.txt.part
 RNFR ./Test.txt.part
 RNTO ./Test.txt

您必须对点进行 url 编码,否则 FtpWebRequest 会将路径“/./”简化为“/”。

I have encountered a similar issue. The problem is that FtpWebRequest (incorrectly) prepends '/' to rename requests, as can be seen from this log (upload & rename):

URL: 
  http://127.0.0.1/Test.txt
FTP log:
  STOR Test.txt.part
  RNFR /Test.txt.part
  RNTO /Test.txt

Please note that this problem occurs only when you are uploading to the root directory. If you changed the URL to http://127.0.0.1/path/Test.txt, then everything would work fine.

My solution to this problem is to use %2E (dot) as the path:

URL:
  http://127.0.0.1/%2E/Test.txt
FTP log:
 STOR ./Test.txt.part
 RNFR ./Test.txt.part
 RNTO ./Test.txt

You have to url-encode the dot, otherwise FtpWebRequest would simplify the path "/./" to "/".

可可 2024-09-12 12:25:43

C#

using System.Net;
using System.IO;

重命名 FTP 服务器上的文件名函数

C#

 private void RenameFileName(string currentFilename, string newFilename)
   {
       FTPSettings.IP = "DOMAIN NAME";
       FTPSettings.UserID = "USER ID";
       FTPSettings.Password = "PASSWORD";
       FtpWebRequest reqFTP = null;
       Stream ftpStream = null ;
       try
       {

           reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FTPSettings.IP + "/" + currentFilename));
           reqFTP.Method = WebRequestMethods.Ftp.Rename;
           reqFTP.RenameTo = newFilename;
           reqFTP.UseBinary = true;
           reqFTP.Credentials = new NetworkCredential(FTPSettings.UserID, FTPSettings.Password);
           FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
           ftpStream = response.GetResponseStream();
           ftpStream.Close();
           response.Close();
       }
       catch (Exception ex)
       {
           if (ftpStream != null)
           {
               ftpStream.Close();
               ftpStream.Dispose();
           }
           throw new Exception(ex.Message.ToString());
       }
   }

   public static class FTPSettings
   {
       public static string IP { get; set; }
       public static string UserID { get; set; }
       public static string Password { get; set; }
   }

C#

using System.Net;
using System.IO;

Rename Filename on FTP Server function

C#

 private void RenameFileName(string currentFilename, string newFilename)
   {
       FTPSettings.IP = "DOMAIN NAME";
       FTPSettings.UserID = "USER ID";
       FTPSettings.Password = "PASSWORD";
       FtpWebRequest reqFTP = null;
       Stream ftpStream = null ;
       try
       {

           reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FTPSettings.IP + "/" + currentFilename));
           reqFTP.Method = WebRequestMethods.Ftp.Rename;
           reqFTP.RenameTo = newFilename;
           reqFTP.UseBinary = true;
           reqFTP.Credentials = new NetworkCredential(FTPSettings.UserID, FTPSettings.Password);
           FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
           ftpStream = response.GetResponseStream();
           ftpStream.Close();
           response.Close();
       }
       catch (Exception ex)
       {
           if (ftpStream != null)
           {
               ftpStream.Close();
               ftpStream.Dispose();
           }
           throw new Exception(ex.Message.ToString());
       }
   }

   public static class FTPSettings
   {
       public static string IP { get; set; }
       public static string UserID { get; set; }
       public static string Password { get; set; }
   }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文