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に解決されます)。
このようにディレクトリ間でファイルを移動することは可能でしょうか?そうでない場合、どうすれば可能ですか?
提起されたポイント/提案のいくつかに対処するには:
さらに、ディレクトリパスを次のように設定してみました。
ftp://1.1.1.1/%2fMAIN/Dir1/MyFile.txt
ソースパスとターゲットパスの両方-ただし、これでも違いはありません。
私は this の記事を見つけました。これは、宛先を相対パスとして指定すると役立つと思われるようです。宛先として絶対パスを指定することはできないようです。
reqFTP.RenameTo = “../Dir2/MyFile.txt";
[〜#〜] msdn [〜#〜] は、パスが相対パスと見なされているため、提供された資格情報を使用してFTPサーバーにログインし、現在のディレクトリを<UserLoginDirectory>/path
ディレクトリに設定します。これがファイルと同じディレクトリでない場合は、550エラーが発生します。
同じ問題があり、問題を解決する別の方法を見つけました:
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;
}
次のコード例では、次のデータを試してみましたが、うまくいきました。
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();
絶対パスしかない場合はどうなりますか?
わかりました。同じエラーが発生したため、この投稿を見つけました。答えは相対パスを使用することです。これは、フォルダーパスを絶対パス文字列として取得するため、私の問題の解決策としてはあまり適していません。
私がその場で思いついた解決策は機能しますが、控えめに言っても醜いです。私はこれをコミュニティー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;
}
私はこれを機能させることができましたが、サーバーに存在するパス、つまり/DRIVELETTER:/FOLDERNAME/filename
in RenameTo = "
コードは正しいようです。したがって、パスが間違っているか、ファイルが存在しないか、大文字と小文字を区別する必要があります(明らかに、Windowsでは大文字と小文字が区別されませんが、Linux、Unixでは区別されます)。
ブラウザでファイルを開こうとしましたか? Windowsファイルエクスプローラーを開き、パスバーにアドレスを入力して、表示される内容を確認します。
これらのフォルダはFTPサービスで定義されていますか? FTPサービスは実行されていますか?いずれかの質問に対する回答が「いいえ」の場合、FTPを使用してファイルを移動することはできません。
FTPクライアントでFTPフォルダーを開いてみて、何が起こるかを確認してください。それでもエラーが発生する場合は、FTPサービスがフォルダーを認識していないか、フォルダーが論理的にFTPサービス内にあると思われる場所にフォルダーが存在しないため、定義に問題があります。
IISマネージャを開いて、FTPでの設定方法を確認することもできます。
ファイルを移動する他の方法については、プログラムが実行されるアカウントに両方への適切なアクセス許可がある限り、UNCパスから別の方法に簡単に移動できます。 UNCパスはHTTPまたはFTPパスに似ており、反対方向に攻撃し、プロトコルは指定されていません。