Примечание: из-за механизма предотвращения спама я был вынужден заменить начало Uris с ftp: // на ftp.
У меня следующая проблема. Я должен загрузить файл с C # ftp методом, а затем переименовать его. Легко, правда? :)
Хорошо, допустим, мой ftp-хост выглядит так:
ftp.contoso.com
и после входа в систему текущий каталог устанавливается на:
Пользователи / имя
Итак, я пытаюсь войти в систему, загрузить файл в текущий каталог как file.ext.tmp и после успешной загрузки переименовать файл в file.ext
Вся сложность заключается, как я полагаю, в правильной установке запроса Uri для FtpWebRequest.
Состояния MSDN:
URI может быть относительным или абсолютным. Если URI имеет форму " ftp: //contoso.com/%2fpath" (% 2f - экранированный '/'), тогда URI является абсолютным, и текущим каталогом является / path. Однако, если URI имеет вид « ftp: //contoso.com/path», сначала .NET Framework входит на FTP-сервер (используя имя пользователя и пароль, установленные свойством Credentials. ), тогда текущим каталогом является UserLoginDirectory / path.
Хорошо, я загружаю файл со следующим URI:
ftp.contoso.com / file.ext.tmp
Отлично, файл находится там, где я хотел: в каталоге "users / name"
Теперь я хочу переименовать файл, поэтому я создаю веб-запрос со следующим Uri:
ftp.contoso.com / file.ext.tmp
и укажите переименование параметра как:
file.ext
и это дает ошибку 550: файл не найден, нет разрешений и т. Д.
Я отследил это в Microsoft Network Monitor, и он дал мне:
Команда: RNFR, Переименовать из
CommandParameter: /file.ext.tmp
Ftp: Ответ на порт 53724, «Файл 550 /file.ext.tmp не найден»
как будто он искал файл в корневом каталоге, а не в текущем каталоге.
Я переименовал файл вручную, используя Total Commander, и единственное отличие заключалось в том, что CommandParameter был без первой косой черты:
CommandParameter: file.ext.tmp
Я могу успешно переименовать файл, указав следующий абсолютный URI:
ftp.contoso.com /% 2fusers /% 2fname / file.ext.tmp
но мне не нравится этот подход, так как мне нужно знать имя каталога текущего пользователя. Вероятно, это можно сделать с помощью WebRequestMethods.Ftp.PrintWorkingDirectory, но это добавляет дополнительную сложность (вызов этого метода для получения имени каталога, затем объединение путей для формирования правильного URI).
Что я не понимаю, так это почему URI ftp.contoso.com/file.ext.tmp подходит для загрузки, а не для переименования? Я что-то здесь упускаю?
Проект настроен на .NET 4.0, кодирован в Visual Studio 2010.
Редактировать
Хорошо, я помещаю фрагмент кода.
Обратите внимание, что FTP-хост, имя пользователя и пароль должны быть заполнены. Чтобы этот пример работал - то есть выдает ошибку - каталог пользователя должен отличаться от корневого (команда "pwd" должна возвращать что-то отличное от "/")
class Program
{
private const string fileName = "test.ext";
private const string tempFileName = fileName + ".tmp";
private const string ftpHost = "127.0.0.1";
private const string ftpUserName = "anonymous";
private const string ftpPassword = "";
private const int bufferSize = 524288;
static void Main(string[] args)
{
try
{
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fileName);
if (!File.Exists(path))
File.WriteAllText(path, "FTP RENAME SAMPLE");
string requestUri = "ftp://" + ftpHost + "/" + tempFileName;
//upload
FtpWebRequest uploadRequest = (FtpWebRequest)WebRequest.Create(requestUri);
uploadRequest.UseBinary = true;
uploadRequest.UsePassive = true;
uploadRequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
uploadRequest.KeepAlive = true;
uploadRequest.Method = WebRequestMethods.Ftp.UploadFile;
Stream requestStream = null;
FileStream localFileStream = null;
localFileStream = File.OpenRead(path);
requestStream = uploadRequest.GetRequestStream();
byte[] buffer = new byte[bufferSize];
int readCount = localFileStream.Read(buffer, 0, bufferSize);
long bytesSentCounter = 0;
while (readCount > 0)
{
requestStream.Write(buffer, 0, readCount);
bytesSentCounter += readCount;
readCount = localFileStream.Read(buffer, 0, bufferSize);
System.Threading.Thread.Sleep(100);
}
localFileStream.Close();
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)uploadRequest.GetResponse();
FtpStatusCode code = response.StatusCode;
string description = response.StatusDescription;
response.Close();
if (code == FtpStatusCode.ClosingData)
Console.WriteLine("File uploaded successfully");
//rename
FtpWebRequest renameRequest = (FtpWebRequest)WebRequest.Create(requestUri);
renameRequest.UseBinary = true;
renameRequest.UsePassive = true;
renameRequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
renameRequest.KeepAlive = true;
renameRequest.Method = WebRequestMethods.Ftp.Rename;
renameRequest.RenameTo = fileName;
try
{
FtpWebResponse renameResponse = (FtpWebResponse)renameRequest.GetResponse();
Console.WriteLine("Rename OK, status code: {0}, rename status description: {1}", response.StatusCode, response.StatusDescription);
renameResponse.Close();
}
catch (WebException ex)
{
Console.WriteLine("Rename failed, status code: {0}, rename status description: {1}", ((FtpWebResponse)ex.Response).StatusCode,
((FtpWebResponse)ex.Response).StatusDescription);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
Console.ReadKey();
}
}
}