Как я могу использовать 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";
Ответы
Ответ 1
MSDN кажется, что ваш путь считается относительным, и поэтому он пытается войти в FTP сервер, используя предоставленные учетные данные, затем устанавливает текущий каталог в каталог <UserLoginDirectory>/path
. Если это не тот каталог, где находится ваш файл, вы получите ошибку 550.
Ответ 2
Имел ту же проблему и нашел другой способ решить проблему:
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;
}
Ответ 3
Мне удалось получить эту работу, но только с использованием пути, который существует на сервере, т.е. /DRIVELETTER:/FOLDERNAME/filename
в RenameTo = "
Ответ 4
Что делать, если у вас есть только абсолютные пути?
Хорошо, я столкнулся с этим сообщением, потому что получал ту же ошибку. Ответ, похоже, заключается в использовании относительного пути, что не очень хорошо для решения моей проблемы, потому что я получаю пути к папкам как абсолютные строки пути.
Решения, которые я придумал на лету, но, по крайней мере, уродливые. Я сделаю это ответ 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;
}
Ответ 5
В следующем примере кода я попытался использовать следующие данные, и он работает.
Местоположение 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();
Ответ 6
У вас есть папки, определенные в службе FTP? Работает ли FTP-сервис? Если ответ на любой вопрос отсутствует, вы не можете использовать FTP для перемещения файлов.
Попробуйте открыть папку FTP в FTP-клиенте и посмотреть, что произойдет. Если у вас все еще есть ошибка, что-то не так с вашим определением, поскольку служба FTP не видит папку, или папка не является логически там, где вы думаете, что она находится в службе FTP.
Вы также можете открыть диспетчер IIS и посмотреть, как все настроено на FTP.
Как и в других способах перемещения файлов, вы можете легко перейти от UNC-пути к другому, если у учетной записи, с которой работает программа, есть соответствующие разрешения для обоих. Путь UNC похож на HTTP или FTP-путь, с ударами в противоположном направлении и не указанным протоколом.
Ответ 7
Код выглядит правильно. Таким образом, либо у вас есть неправильный путь, файл DOESNT существует, либо вам нужно уважать дело (очевидно, что Windows не чувствительна к регистру, но Linux, Unix).
Вы пытались открыть файл в браузере? Откройте Windows File Explorer и введите адрес на панели путей и посмотрите, что вы получаете.
Ответ 8
Я работаю над идентичным типом проекта, попробуйте создать веб-службу, которая может перемещать файлы и запускаться на сервере, где находятся ваши файлы. Постройте его с параметром для передачи имени файла. Когда вы начинаете писать файл, вы можете добавить значение к имени файла, скажем, PK данных, которые коррелируют с файлом и т.д.