10

備考:スパム防止メカニズムのため、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();
        }
    }
}
4

2 に答える 2

8

同様の問題が発生しました。問題は、このログ (アップロードと名前の変更) からわかるように、FtpWebRequest が (誤って) 名前の変更要求に「/」を追加することです。

URL: 
  http://127.0.0.1/Test.txt
FTP log:
  STOR Test.txt.part
  RNFR /Test.txt.part
  RNTO /Test.txt

この問題は、ルート ディレクトリにアップロードする場合にのみ発生することに注意してください。URL を に変更するとhttp://127.0.0.1/path/Test.txt、すべて正常に動作します。

この問題に対する私の解決策は、パスとして %2E (ドット) を使用することです。

URL:
  http://127.0.0.1/%2E/Test.txt
FTP log:
 STOR ./Test.txt.part
 RNFR ./Test.txt.part
 RNTO ./Test.txt

ドットを URL エンコードする必要があります。そうしないと、FtpWebRequest がパス「/./」を「/」に簡略化してしまいます。

于 2012-02-21T10:19:01.120 に答える
4

C#

using System.Net;
using System.IO;

FTPサーバーのファイル名変更機能

C#

 private void RenameFileName(string currentFilename, string newFilename)
   {
       FTPSettings.IP = "DOMAIN NAME";
       FTPSettings.UserID = "USER ID";
       FTPSettings.Password = "PASSWORD";
       FtpWebRequest reqFTP = null;
       Stream ftpStream = null ;
       try
       {

           reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FTPSettings.IP + "/" + currentFilename));
           reqFTP.Method = WebRequestMethods.Ftp.Rename;
           reqFTP.RenameTo = newFilename;
           reqFTP.UseBinary = true;
           reqFTP.Credentials = new NetworkCredential(FTPSettings.UserID, FTPSettings.Password);
           FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
           ftpStream = response.GetResponseStream();
           ftpStream.Close();
           response.Close();
       }
       catch (Exception ex)
       {
           if (ftpStream != null)
           {
               ftpStream.Close();
               ftpStream.Dispose();
           }
           throw new Exception(ex.Message.ToString());
       }
   }

   public static class FTPSettings
   {
       public static string IP { get; set; }
       public static string UserID { get; set; }
       public static string Password { get; set; }
   }
于 2011-05-21T07:32:03.367 に答える