Как использовать 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-сайт (он находится на моем локальном ПК, и uri разрешен на localhost).
можно ли перемещать файлы между такими каталогами, а если нет, то как это возможно?
для решения некоторых вопросов / предложений, которые были подняты:
- я могу загрузить тот же файл из исходный каталог, поэтому он определенно существует (что я делаю, так это сначала загружаю файл, а затем перемещаю его куда-то еще).
- я могу получить доступ к ftp-сайту из браузера (как исходный, так и целевой каталог)
- ftp-сервер работает под моим собственным экземпляром IIS на моей локальной машине.
- путь и дела верны и нет никаких специальных символов.
кроме того, я попытался установить путь к каталогу быть:
ftp://1.1.1.1/%2fMAIN/Dir1/MyFile.txt
как для исходного, так и для целевого пути - но это тоже не имеет значения.
нашел этой статья, которая, кажется, говорит, что указание места назначения в качестве относительного пути поможет - не представляется возможным указать абсолютный путь в качестве места назначения.
reqFTP.RenameTo = “../Dir2/MyFile.txt";
9 ответов
MSDN похоже, что ваш путь считается относительным, и поэтому он пытается войти на FTP-сервер, используя предоставленные учетные данные, а затем устанавливает текущий каталог в . Если это не тот же каталог, где ваш файл, вы получите ошибку 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
в RenameTo = "
Что делать, если у вас есть только абсолютные пути?
хорошо, я наткнулся на этот пост, потому что я получал ту же ошибку. Ответ, похоже, заключается в использовании относительного пути, что не очень хорошо для решения моей проблемы, потому что я получаю пути к папкам как абсолютные строки пути.
решения, которые я придумал на лету, работают, но, мягко говоря, уродливы. Я сделаю это ответом сообщества wiki, и если у кого-то есть лучшее решение, не стесняйтесь редактировать это.
Так как я узнал это, у меня есть 2 решения.
-
возьмите абсолютный путь от перемещения к пути и преобразуйте его в относительный 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(); }
или...
-
загрузите файл из пути "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\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();
У вас есть эти папки, определенные в службе FTP? Работает ли служба FTP? Если ответ на один вопрос нет, вы не можете использовать FTP для перемещения файлов.
попробуйте открыть папку FTP в FTP-клиенте и посмотреть, что произойдет. Если у вас все еще есть ошибка, что-то не так с вашим определением, поскольку служба FTP не видит папку или папка не логически, где вы думаете, что она находится в службе FTP.
вы также можете открыть Диспетчер IIS и посмотрите, как все настроено в FTP.
Что касается других методов перемещения файлов, вы можете легко перейти с пути UNC на другой, если учетная запись, под которой работает программа, имеет соответствующие разрешения для обоих. Путь UNC похож на путь HTTP или FTP, с ударами в противоположном направлении и без указанного протокола.
код выглядит правильно. Таким образом, либо у вас неправильный путь, файл не существует, либо вам нужно уважать регистр (очевидно, Windows не чувствительна к регистру, но Linux, Unix).
вы пытались открыть файл в браузере? Откройте Проводник файлов Windows и введите адрес в строке пути и посмотрите, что вы получите.
U может использовать этот код:
исходное местоположение файла"ftp://example.com/directory1/Somefile.file".
файл для перемещения, " / newDirectory / Somefile.папка."
обратите внимание, что 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;
Я работаю над идентичным типом проекта, попробуйте создать веб-службу, которая может перемещать файлы и работать на сервере, где находятся ваши файлы. Создайте его с параметром для передачи имени файла. При записи файла для начала вы можете добавить значение к имени файла, скажем, PK данных, которые коррелируют с файлом и т. д.