【问题标题】:How can I use FTP to move files between directories?如何使用 FTP 在目录之间移动文件?
【发布时间】:2011-06-19 09:25:25
【问题描述】:

我有一个程序需要在 FTP 服务器上将文件从一个目录移动到另一个目录。例如文件在:

ftp://1.1.1.1/MAIN/Dir1

我需要将文件移动到:

ftp://1.1.1.1/MAIN/Dir2

我找到了几篇推荐使用重命名命令的文章,所以我尝试了以下方法:

    Uri serverFile = new Uri(“ftp://1.1.1.1/MAIN/Dir1/MyFile.txt");
    FtpWebRequest reqFTP= (FtpWebRequest)FtpWebRequest.Create(serverFile);
    reqFTP.Method = WebRequestMethods.Ftp.Rename;
    reqFTP.UseBinary = true;
    reqFTP.Credentials = new NetworkCredential(ftpUser, ftpPass);
    reqFTP.RenameTo = “ftp://1.1.1.1/MAIN/Dir2/MyFile.txt";

    FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();

但这似乎不起作用 - 我收到以下错误:

远程服务器返回错误:(550) 文件不可用(例如,找不到文件,无法访问)。

起初我认为这可能与权限有关,但据我所知,我拥有整个 FTP 站点的权限(它在我的本地 PC 上,并且 uri 被解析为 localhost)。

应该可以像这样在目录之间移动文件吗,如果没有,怎么可能?

解决一些已提出的观点/建议:

  1. 我可以从源目录下载相同的文件,所以它肯定存在(我正在做的是先下载文件,然后将它移动到其他地方)。
  2. 我可以从浏览器(源目录和目标目录)访问 ftp 站点
  3. ftp 服务器在我本地机器上我自己的 IIS 实例下运行。
  4. 路径和大小写正确,没有特殊字符。

另外,我尝试将目录路径设置为:

ftp://1.1.1.1/%2fMAIN/Dir1/MyFile.txt

对于源路径和目标路径 - 但这也没有区别。

我找到了this 文章,它似乎说将目标指定为相对路径会有所帮助 - 似乎无法将绝对路径指定为目标。

reqFTP.RenameTo = “../Dir2/MyFile.txt";

【问题讨论】:

  • 如果您将1.1.1.1/MAIN/Dir1/MyFile.txt 插入浏览器,它可以工作吗?
  • 路径中是否包含需要转义的特殊字符?
  • 查看最新的编辑,但答案是:是的 - 它确实可以在浏览器中工作,不 - 路径没有特殊字符
  • @PaulMichaels 这是如何解决的?只是通过使用 .Rename 方法? :D
  • @Roxy'Pro - 恐怕我的记性不太好。鉴于我将 vlad 的答案标记为正确,我想这至少让我找到了解决方案。

标签: c# .net-3.5 ftp ftpwebrequest


【解决方案1】:

遇到了同样的问题,找到了另一种解决问题的方法:

public string FtpRename( string source, string destination ) {
        if ( source == destination )
            return;

        Uri uriSource = new Uri( this.Hostname + "/" + source ), UriKind.Absolute );
        Uri uriDestination = new Uri( this.Hostname + "/" + destination ), UriKind.Absolute );

        // Do the files exist?
        if ( !FtpFileExists( uriSource.AbsolutePath ) ) {
            throw ( new FileNotFoundException( string.Format( "Source '{0}' not found!", uriSource.AbsolutePath ) ) );
        }

        if ( FtpFileExists( uriDestination.AbsolutePath ) ) {
            throw ( new ApplicationException( string.Format( "Target '{0}' already exists!", uriDestination.AbsolutePath ) ) );
        }

        Uri targetUriRelative = uriSource.MakeRelativeUri( uriDestination );


        //perform rename
        FtpWebRequest ftp = GetRequest( uriSource.AbsoluteUri );
        ftp.Method = WebRequestMethods.Ftp.Rename;
        ftp.RenameTo = Uri.UnescapeDataString( targetUriRelative.OriginalString );

        FtpWebResponse response = (FtpWebResponse)ftp.GetResponse(); 

        return response.StatusDescription; 

    }

【讨论】:

    【解决方案2】:

    MSDN 似乎表明您的路径被认为是相对的,因此它会尝试使用提供的凭据登录到 FTP 服务器,然后将当前目录设置为<UserLoginDirectory>/path 目录。如果这与您的文件所在的目录不同,您将收到 550 错误。

    【讨论】:

    • 查看最新编辑。我在路径中尝试了 %2f 的各种组合,但没有成功
    • 我更新了问题 - 看起来你是对的,但无论我尝试什么,我都没有找到绝对的工作路径。
    • 很好的发现。如果这是我的问题,我可能需要一段时间才能弄清楚这个问题。
    • 我之所以知道它,是因为我经常浏览那些相同的页面(FTPWebRequest 等)来寻找我正在创建的东西
    • 我需要一个类似的功能。但是,目标 ftp 位置具有不同的凭据,而源具有不同的凭据。有人可以建议我如何最好地进行吗?
    【解决方案3】:

    在下面的代码示例中,我尝试了以下数据并且它有效。

    FTP 登录位置是C:\FTP

    文件原位置C:\FTP\Data\FTP.txt

    要移动的文件,C:\FTP\Move\FTP.txt

    Uri serverFile = new Uri("ftp://localhost/Data/FTP.txt");
    FtpWebRequest reqFTP= (FtpWebRequest)FtpWebRequest.Create(serverFile);
    reqFTP.Method = WebRequestMethods.Ftp.Rename;
    reqFTP.Credentials = new NetworkCredential(ftpUser, ftpPass);
    reqFTP.RenameTo = "../Move/FTP.txt";
    
    FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
    

    【讨论】:

      【解决方案4】:

      我能够让这个工作,但只能通过使用服务器上存在的路径,即/DRIVELETTER:/FOLDERNAME/filename in RenameTo = "

      【讨论】:

        【解决方案5】:

        如果你只有绝对路径怎么办?

        好的,我遇到了这篇文章,因为我遇到了同样的错误。答案似乎是使用相对路径,这对于我的问题不是很好的解决方案,因为我将文件夹路径作为绝对路径字符串。

        我想出的解决方案很有效,但至少可以说是丑陋的。我会将其作为社区 wiki 答案,如果有人有更好的解决方案,请随时编辑。

        自从我了解到这一点后,我有 2 个解决方案。

        1. 从移动到路径中获取绝对路径,并将其转换为相对 URL。

          public static string GetRelativePath(string ftpBasePath, string ftpToPath)
          {
          
              if (!ftpBasePath.StartsWith("/"))
              {
                  throw new Exception("Base path is not absolute");
              }
              else
              {
                  ftpBasePath =  ftpBasePath.Substring(1);
              }
              if (ftpBasePath.EndsWith("/"))
              {
                  ftpBasePath = ftpBasePath.Substring(0, ftpBasePath.Length - 1);
              }
          
              if (!ftpToPath.StartsWith("/"))
              {
                  throw new Exception("Base path is not absolute");
              }
              else
              {
                  ftpToPath = ftpToPath.Substring(1);
              }
              if (ftpToPath.EndsWith("/"))
              {
                  ftpToPath = ftpToPath.Substring(0, ftpToPath.Length - 1);
              }
              string[] arrBasePath = ftpBasePath.Split("/".ToCharArray());
              string[] arrToPath = ftpToPath.Split("/".ToCharArray());
          
              int basePathCount = arrBasePath.Count();
              int levelChanged = basePathCount;
              for (int iIndex = 0; iIndex < basePathCount; iIndex++)
              {
                  if (arrToPath.Count() > iIndex)
                  {
                      if (arrBasePath[iIndex] != arrToPath[iIndex])
                      {
                          levelChanged = iIndex;
                          break;
                      }
                  }
              }
              int HowManyBack = basePathCount - levelChanged;
              StringBuilder sb = new StringBuilder();
              for (int i = 0; i < HowManyBack; i++)
              {
                  sb.Append("../");
              }
              for (int i = levelChanged; i < arrToPath.Count(); i++)
              {
                  sb.Append(arrToPath[i]);
                  sb.Append("/");
              }
          
              return sb.ToString();
          }
          
          public static string MoveFile(string ftpuri, string username, string password, string ftpfrompath, string ftptopath, string filename)
          {
              string retval = string.Empty;
          
              FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(ftpuri + ftpfrompath + filename);
              ftp.Method = WebRequestMethods.Ftp.Rename;
              ftp.Credentials = new NetworkCredential(username, password);
              ftp.UsePassive = true;
              ftp.RenameTo = GetRelativePath(ftpfrompath, ftptopath) + filename;
              Stream requestStream = ftp.GetRequestStream();
          
          
              FtpWebResponse ftpresponse = (FtpWebResponse)ftp.GetResponse();
          
              Stream responseStream = ftpresponse.GetResponseStream();
          
              StreamReader reader = new StreamReader(responseStream);
          
              return reader.ReadToEnd();
          }
          

        或者...

        1. 从“ftp from”路径下载文件,上传到“ftp to”路径,然后从“ftp from”路径中删除。

          public static string SendFile(string ftpuri, string username, string password, string ftppath, string filename, byte[] datatosend)
          {
              if (ftppath.Substring(ftppath.Length - 1) != "/")
              {
                  ftppath += "/";
              }
              FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(ftpuri + ftppath + filename);
              ftp.Method = WebRequestMethods.Ftp.UploadFile;
              ftp.Credentials = new NetworkCredential(username, password);
              ftp.UsePassive = true;
              ftp.ContentLength = datatosend.Length;
              Stream requestStream = ftp.GetRequestStream();
              requestStream.Write(datatosend, 0, datatosend.Length);
              requestStream.Close();
          
              FtpWebResponse ftpresponse = (FtpWebResponse)ftp.GetResponse();
          
              return ftpresponse.StatusDescription;
          }
          public static string DeleteFile(string ftpuri, string username, string password, string ftppath, string filename)
          {
          
              FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(ftpuri + ftppath + filename);
              ftp.Method = WebRequestMethods.Ftp.DeleteFile;
              ftp.Credentials = new NetworkCredential(username, password);
              ftp.UsePassive = true;
          
              FtpWebResponse response = (FtpWebResponse)ftp.GetResponse();
          
              Stream responseStream = response.GetResponseStream();
          
              StreamReader reader = new StreamReader(responseStream);
          
              return reader.ReadToEnd();
          }
          public static string MoveFile(string ftpuri, string username, string password, string ftpfrompath, string ftptopath, string filename)
          {
              string retval = string.Empty;
              byte[] filecontents = GetFile(ftpuri, username, password, ftpfrompath, filename);
              retval += SendFile(ftpuri, username, password, ftptopath, filename, filecontents);
              retval += DeleteFile(ftpuri, username, password, ftpfrompath, filename);
              return retval;
          }
          

        【讨论】:

          【解决方案6】:

          您是否在 FTP 服务中定义了这些文件夹? FTP 服务是否正在运行?如果任一问题的答案是否定的,则不能使用 FTP 移动文件。

          尝试在 FTP 客户端中打开 FTP 文件夹,看看会发生什么。如果您仍然有错误,则说明您的定义有问题,因为 FTP 服务看不到该文件夹​​,或者该文件夹在逻辑上不在您认为它在 FTP 服务中的位置。

          您还可以打开 IIS 管理器并查看 FTP 中的设置。

          至于其他移动文件的方法,您可以轻松地从 UNC 路径移动到另一个路径,只要运行程序的帐户对两者都具有适当的权限。 UNC 路径类似于 HTTP 或 FTP 路径,方向相反,没有指定协议。

          【讨论】:

            【解决方案7】:

            代码看起来正确。所以要么你的路径错误,文件不存在,要么你需要区分大小写(显然 Windows 不区分大小写,但 Linux、Unix 是)。

            您是否尝试在浏览器中打开该文件?打开 Windows 文件资源管理器并在路径栏中输入地址,看看你得到了什么。

            【讨论】:

              【解决方案8】:

              你可以使用这个代码:

              文件原始位置“ftp://example.com/directory1/Somefile.file”。

              要移动的文件,“/newDirectory/Somefile.file”。

              请注意,目标 URL 不需要以:ftp://example.com 开头

              NetworkCredential User = new NetworkCredential("UserName", "password");
              FtpWebRequest Wr =FtpWebRequest)FtpWebRequest.Create("ftp://Somwhere.com/somedirectory/Somefile.file");
              Wr.UseBinary = true;
              Wr.Method = WebRequestMethods.Ftp.Rename;
              Wr.Credentials = User;
              Wr.RenameTo = "/someotherDirectory/Somefile.file";
              back = (FtpWebResponse)Wr.GetResponse();
              bool Success = back.StatusCode == FtpStatusCode.CommandOK || back.StatusCode == FtpStatusCode.FileActionOK;
              

              【讨论】:

                【解决方案9】:

                我正在处理相同类型的项目,尝试构建一个可以移动文件并在文件所在的服务器上运行的 Web 服务。使用参数构建它以传入文件名。在写入文件开始时,您可能希望在文件名后附加一个值,例如与文件相关的数据的 PK 等。

                【讨论】:

                • 这应该是评论,而不是答案。
                • @Jester610,你能举例说明一下吗?
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-10-06
                • 2012-03-16
                • 2012-01-09
                • 2016-10-14
                • 1970-01-01
                相关资源
                最近更新 更多