備考:スパム防止メカニズムのため、URIの先頭をftp://からftpに置き換えることを余儀なくされました。
次の問題があります。C#ftpメソッドでファイルをアップロードし、後で名前を変更する必要があります。簡単ですよね?:)
さて、私のftpホストは次のようになっているとしましょう:
ftp.contoso.com
ログイン後、現在のディレクトリは次のように設定されます。
ユーザー/名前
だから、私が達成しようとしているのは、ログインして、ファイルをfile.ext.tmpとして現在のディレクトリにアップロードし、アップロードが成功した後、ファイルの名前をfile.extに変更することです。
全体的な難しさは、私が推測するように、FtpWebRequestのリクエストURIを適切に設定することです。
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を使用してWebリクエストを作成します。
ftp.contoso.com/file.ext.tmp
そして、パラメータの名前変更を次のように指定します。
file.ext
これにより、550エラーが発生します:ファイルが見つからない、権限がないなど。
これをMicrosoftNetworkMonitorで追跡したところ、次のようになりました。
コマンド: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が名前の変更ではなく、アップロードに適している理由です。ここで何かが足りませんか?
プロジェクトは、VisualStudio2010でコーディングされた.NET4.0に設定されています。
編集
OK、コードスニペットを配置します。
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();
}
}
}