23

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 サイト全体へのアクセス許可を持っています (ローカル PC 上にあり、uri は localhost に解決されます)。

このようにディレクトリ間でファイルを移動できるはずですか?そうでない場合、どうすれば可能ですか?

提起されたポイント/提案のいくつかに対処するには:

  1. ソース ディレクトリから同じファイルをダウンロードできるので、間違いなく存在します (最初にファイルをダウンロードしてから別の場所に移動しています)。
  2. ブラウザから ftp サイトにアクセスできます (ソース ディレクトリとターゲット ディレクトリの両方)。
  3. ftp サーバーは、ローカル マシン上の自分の IIS インスタンスで実行されています。
  4. パスと大文字と小文字が正しく、特殊文字はありません。

さらに、ディレクトリ パスを次のように設定しようとしました。

ftp://1.1.1.1/%2fMAIN/Dir1/MyFile.txt

ソースパスとターゲットパスの両方 - しかし、これも違いはありません。

この記事を見つけました。宛先を相対パスで指定すると役立つと思われますが、絶対パスを宛先として指定することはできないようです。

reqFTP.RenameTo = “../Dir2/MyFile.txt";
4

9 に答える 9

19

同じ問題があり、問題を解決する別の方法を見つけました:

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; 

    }
于 2011-09-13T10:28:31.183 に答える
14

MSDNは、パスが相対パスと見なされることを示唆しているようです。そのため、提供された資格情報を使用して FTP サーバーにログインしようとし、現在のディレクトリをその<UserLoginDirectory>/pathディレクトリに設定します。これがファイルと同じディレクトリでない場合は、550 エラーが発生します。

于 2011-02-01T16:19:39.193 に答える
3

次のコード例では、次のデータで試してみましたが、うまくいきました。

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();
于 2016-03-03T07:34:35.357 に答える
1

絶対パスしかない場合はどうなりますか?

OK、同じエラーが発生していたので、この投稿に出くわしました。答えは、フォルダー パスを絶対パス文字列として取得するため、相対パスを使用することです。これは、私の問題の解決策としてはあまり良くありません。

私がその場で思いついた解決策は機能しますが、控えめに言っても醜いです。これをコミュニティ wiki の回答にします。誰かがより良い解決策を持っている場合は、自由に編集してください。

これを学んだので、2つの解決策があります。

  1. move to パスから絶対パスを取得し、相対 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();
    }
    

また...

  1. 「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;
    }
    
于 2011-08-19T00:51:22.797 に答える
1

これを機能させることができましたが、サーバー上に存在するパスを使用することによってのみ、つまり/DRIVELETTER:/FOLDERNAME/filenameRenameTo = "

于 2011-04-11T16:47:47.203 に答える
0

FTP サービスでこれらのフォルダを定義していますか? FTP サービスは実行されていますか? いずれかの質問に対する答えが「いいえ」の場合、FTP を使用してファイルを移動することはできません。

FTP クライアントで FTP フォルダを開いて、何が起こるかを確認してください。それでもエラーが発生する場合は、定義に何か問題があります。FTP サービスがフォルダーを認識しないか、フォルダーが FTP サービス内にあると考えられる場所に論理的に存在しないためです。

また、IIS マネージャーを開いて、FTP での設定を確認することもできます。

ファイルを移動する他の方法については、プログラムを実行するアカウントが両方に対して適切なアクセス許可を持っている限り、UNC パスから別のパスに簡単に移動できます。UNC パスは、HTTP または FTP パスに似ていますが、逆方向に攻撃され、プロトコルが指定されていません。

于 2011-02-01T16:15:03.990 に答える
0

コードは正しいようです。したがって、パスが間違っているか、ファイルが存在しないか、大文字と小文字を区別する必要があります (明らかに、Windows では大文字と小文字が区別されませんが、Linux、Unix では大文字と小文字が区別されます)。

ブラウザでファイルを開こうとしましたか? Windows ファイル エクスプローラーを開き、パス バーにアドレスを入力して、表示される内容を確認します。

于 2011-02-01T16:19:47.480 に答える
-2

私は同じタイプのプロジェクトに取り組んでいます。ファイルを移動して、ファイルがあるサーバー上で実行できる Web サービスを構築してみてください。ファイル名を渡すパラメーターを使用してビルドします。最初にファイルを書き込むとき、ファイル名に値を追加したい場合があります。たとえば、ファイルに関連するデータの PK などです。

于 2012-02-07T19:46:20.870 に答える