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

我有一个程序需要在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. 路径和大小写是正确的,没有特殊字符。

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

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

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

我发现这篇文章,似乎说将目标指定为相对路径会有所帮助 – 似乎不可能将绝对路径指定为目标。

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

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

有同样的问题,并找到另一种方法来解决问题:

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

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

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

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

我已经提出了解决方案,但至少可以说是丑陋的。 我将这个社区维基解答,如果有人有更好的解决方案,请随时编辑。

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

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

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

FTP登录位置为“C:\ FTP”。

文件原始位置“C:\ FTP \ Data \ http://FTP.txt”。

要移动的文件,“C:\ FTP \ Move \ http://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(); 

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

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

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

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

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

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

你可以使用这段代码:

文件原始位置“ 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; 

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