如何使用FTP在目录之间移动文件?

时间:2011-02-01 16:08:35

标签: c# .net-3.5 ftp ftpwebrequest

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

ftp://1.1.1.1/MAIN/Dir1

我需要将文件移动到:

ftp://1.1.1.1/MAIN/Dir2

我发现有几篇文章建议使用Rename命令,所以我尝试了以下内容:

    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. 路径和大小写正确且没有特殊字符。
  5. 此外,我已尝试将目录路径设置为:

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

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

    我发现this文章,似乎说将目的地指定为相对路径会有所帮助 - 似乎无法将绝对路径指定为目的地。

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

9 个答案:

答案 0 :(得分:18)

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

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; 

    }

答案 1 :(得分:12)

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

答案 2 :(得分:2)

在下面的代码示例中,我尝试使用以下数据并且它可以正常工作。

FTP登录位置为&#34; C:\ FTP&#34;。

文件原始位置&#34; C:\ FTP \ Data \ FTP.txt&#34;。

要移动的文件,&#34; C:\ FTP \ Move \ FTP.txt&#34;。

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();

答案 3 :(得分:1)

我能够使用它,但只能使用服务器上存在的路径,即RenameTo中的/DRIVELETTER:/FOLDERNAME/filename =“

答案 4 :(得分:1)

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

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

我在飞行工作中提出的解决方案但至少可以说是丑陋的。我会将此作为社区wiki的答案,如果有人有更好的解决方案,请随时编辑。

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

  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();
    }
    
  2. ...或

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

答案 5 :(得分:0)

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

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

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

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

答案 6 :(得分:0)

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

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

答案 7 :(得分:-1)

U可以使用以下代码:

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

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

请注意,目标网址不需要以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;

答案 8 :(得分:-2)

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