注意:ここで紹介している方法は、.NET Framework 2.0以降でのみ使用できます。.NET Framework 1.1以前でFTPサーバーにアクセスする方法は、「[HOWTO] Visual Basic .NET を使用してプラグ可能なプロトコルを記述し、マネージ クラスで FTP をサポートする方法」や「Visual Basic .NET または Visual Basic 2005 を使用して FTP サイトにアクセスする方法」などをご覧ください。
まずはRETRコマンドでFTPサーバーからファイルをダウンロードする方法を紹介します。
基本的には、「WebRequest、WebResponseクラスを使ってファイルをダウンロードし保存する」で紹介した方法と同じです。FtpWebRequestの場合、MethodプロパティにWebRequestMethods.Ftp.DownloadFileを指定することにより、ダウンロードすることができます(何も指定しなかった時も、WebRequestMethods.Ftp.DownloadFileを指定したのと同じになります)。
以下の例では、"ftp://localhost/test.txt"から"test.txt"をダウンロードして、"C:\test.txt"に保存しています。FTPサーバーへのログインユーザー名は"username"、パスワードは"password"であるものとします。
'ダウンロードするファイルのURI Dim u As New Uri("ftp://localhost/test.txt") 'ダウンロードしたファイルの保存先 Dim downFile As String = "C:\test.txt" 'FtpWebRequestの作成 Dim ftpReq As System.Net.FtpWebRequest = _ CType(System.Net.WebRequest.Create(u), System.Net.FtpWebRequest) 'ログインユーザー名とパスワードを設定 ftpReq.Credentials = New System.Net.NetworkCredential("username", "password") 'MethodにWebRequestMethods.Ftp.DownloadFile("RETR")を設定 ftpReq.Method = System.Net.WebRequestMethods.Ftp.DownloadFile '要求の完了後に接続を閉じる ftpReq.KeepAlive = False 'ASCIIモードで転送する ftpReq.UseBinary = False 'PASSIVEモードを無効にする ftpReq.UsePassive = False 'FtpWebResponseを取得 Dim ftpRes As System.Net.FtpWebResponse = _ CType(ftpReq.GetResponse(), System.Net.FtpWebResponse) 'ファイルをダウンロードするためのStreamを取得 Dim resStrm As System.IO.Stream = ftpRes.GetResponseStream() 'ダウンロードしたファイルを書き込むためのFileStreamを作成 Dim fs As New System.IO.FileStream( _ downFile, System.IO.FileMode.Create, System.IO.FileAccess.Write) 'ダウンロードしたデータを書き込む Dim buffer(1023) As Byte While True Dim readSize As Integer = resStrm.Read(buffer, 0, buffer.Length) If readSize = 0 Then Exit While End If fs.Write(buffer, 0, readSize) End While fs.Close() resStrm.Close() 'FTPサーバーから送信されたステータスを表示 Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription) '閉じる ftpRes.Close()
//ダウンロードするファイルのURI Uri u = new Uri("ftp://localhost/test.txt"); //ダウンロードしたファイルの保存先 string downFile = "C:\\test.txt"; //FtpWebRequestの作成 System.Net.FtpWebRequest ftpReq = (System.Net.FtpWebRequest) System.Net.WebRequest.Create(u); //ログインユーザー名とパスワードを設定 ftpReq.Credentials = new System.Net.NetworkCredential("username", "password"); //MethodにWebRequestMethods.Ftp.DownloadFile("RETR")を設定 ftpReq.Method = System.Net.WebRequestMethods.Ftp.DownloadFile; //要求の完了後に接続を閉じる ftpReq.KeepAlive = false; //ASCIIモードで転送する ftpReq.UseBinary = false; //PASSIVEモードを無効にする ftpReq.UsePassive = false; //FtpWebResponseを取得 System.Net.FtpWebResponse ftpRes = (System.Net.FtpWebResponse)ftpReq.GetResponse(); //ファイルをダウンロードするためのStreamを取得 System.IO.Stream resStrm = ftpRes.GetResponseStream(); //ダウンロードしたファイルを書き込むためのFileStreamを作成 System.IO.FileStream fs = new System.IO.FileStream( downFile, System.IO.FileMode.Create, System.IO.FileAccess.Write); //ダウンロードしたデータを書き込む byte[] buffer = new byte[1024]; while (true) { int readSize = resStrm.Read(buffer, 0, buffer.Length); if (readSize == 0) break; fs.Write(buffer, 0, readSize); } fs.Close(); resStrm.Close(); //FTPサーバーから送信されたステータスを表示 Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription); //閉じる ftpRes.Close();
上記の例では、FtpWebRequest.KeepAliveプロパティをfalseにしていますので、FtpWebResponseのCloseメソッドが呼び出された時に、ログアウトしてサーバーとの接続が切断されます。KeepAliveプロパティがtrueの時(デフォルト)は、FtpWebResponse.Closeメソッドが呼び出されてもログアウトせず、接続は継続されます。これについて詳しくは、後述します。
また、FtpWebRequest.UseBinaryをfalseにして、ASCIIモード("Type A"コマンド)で転送しています。デフォルトはtrueで、バイナリモード("TYPE I"コマンド)で転送されます。ASCIIモードでは、通常改行コードが変換されます(ファイルをダウンロードするときはLFをCR+LFに、アップロードするときはCR+LFをLFに変換)。バイナリモードでは、変換されません。ただし、サーバーがこのコマンドを無視する可能性もあります。UseBinaryのデフォルトはTrueです。
さらに、FtpWebRequest.UsePassiveをfalseにして、PASVモード(パッシブモード)を使わないようにしています。パッシブモードでは、データ転送用のポートをクライアント側が指定します。通常ファイアウォールの内側から外部のFTPサーバーに接続する場合は、パッシブモードにしないと接続できません。UsePassiveプロパティのデフォルトはtrueで、PASVモードになります。
なお、ダウンロードするファイルがFTPサーバーに存在しなかった場合は、FtpWebResponse.GetResponseメソッドを呼び出した時に、例外WebExceptionがスローされます。例外がスローされた時に原因を調べる方法は、後述します。
上記の例では、URIを"ftp://localhost/test.txt"としていますが、このURIはFTPサーバーにログインした時のディレクトリからの相対パスになります。具体的には、例えばFTPサーバーにログインした時のディレクトリが"public_html"であったならば、"public_html"ディレクトリの"test.txt"がダウンロードされます。
絶対パスのURIにするには、"ftp://localhost/%2ftest.txt"とし、"/"をエスケープした"%2f"を使用します。このようにすると、ルートディレクトリにある"test.txt"がダウンロードされます。
"STOR"コマンドでFTPサーバーにファイルをアップロードするには、FtpWebRequestのMethodプロパティにWebRequestMethods.Ftp.UploadFileを指定します。"STOR"コマンドでは、同名のファイルがサーバーに存在すると、上書きされます。
アップロードするデータは、FtpWebRequest.GetRequestStreamメソッドで取得したストリームに書き込みます。これは、「POSTによりデータを送受信する」と同じです。
以下の例では、"C:\test.txt"を"ftp://localhost/test.txt"にアップロードしています。
'アップロードするファイル Dim upFile As String = "C:\test.txt" 'アップロード先のURI Dim u As New Uri("ftp://localhost/test.txt") 'FtpWebRequestの作成 Dim ftpReq As System.Net.FtpWebRequest = _ CType(System.Net.WebRequest.Create(u), System.Net.FtpWebRequest) 'ログインユーザー名とパスワードを設定 ftpReq.Credentials = New System.Net.NetworkCredential("username", "password") 'MethodにWebRequestMethods.Ftp.UploadFile("STOR")を設定 ftpReq.Method = System.Net.WebRequestMethods.Ftp.UploadFile '要求の完了後に接続を閉じる ftpReq.KeepAlive = False 'ASCIIモードで転送する ftpReq.UseBinary = False 'PASVモードを無効にする ftpReq.UsePassive = False 'ファイルをアップロードするためのStreamを取得 Dim reqStrm As System.IO.Stream = ftpReq.GetRequestStream() 'アップロードするファイルを開く Dim fs As New System.IO.FileStream( _ upFile, System.IO.FileMode.Open, System.IO.FileAccess.Read) 'アップロードStreamに書き込む Dim buffer(1023) As Byte While True Dim readSize As Integer = fs.Read(buffer, 0, buffer.Length) If readSize = 0 Then Exit While End If reqStrm.Write(buffer, 0, readSize) End While fs.Close() reqStrm.Close() 'FtpWebResponseを取得 Dim ftpRes As System.Net.FtpWebResponse = _ CType(ftpReq.GetResponse(), System.Net.FtpWebResponse) 'FTPサーバーから送信されたステータスを表示 Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription) '閉じる ftpRes.Close()
//アップロードするファイル string upFile = "C:\\test.txt"; //アップロード先のURI Uri u = new Uri("ftp://localhost/test.txt"); //FtpWebRequestの作成 System.Net.FtpWebRequest ftpReq = (System.Net.FtpWebRequest) System.Net.WebRequest.Create(u); //ログインユーザー名とパスワードを設定 ftpReq.Credentials = new System.Net.NetworkCredential("username", "password"); //MethodにWebRequestMethods.Ftp.UploadFile("STOR")を設定 ftpReq.Method = System.Net.WebRequestMethods.Ftp.UploadFile; //要求の完了後に接続を閉じる ftpReq.KeepAlive = false; //ASCIIモードで転送する ftpReq.UseBinary = false; //PASVモードを無効にする ftpReq.UsePassive = false; //ファイルをアップロードするためのStreamを取得 System.IO.Stream reqStrm = ftpReq.GetRequestStream(); //アップロードするファイルを開く System.IO.FileStream fs = new System.IO.FileStream( upFile, System.IO.FileMode.Open, System.IO.FileAccess.Read); //アップロードStreamに書き込む byte[] buffer = new byte[1024]; while (true) { int readSize = fs.Read(buffer, 0, buffer.Length); if (readSize == 0) break; reqStrm.Write(buffer, 0, readSize); } fs.Close(); reqStrm.Close(); //FtpWebResponseを取得 System.Net.FtpWebResponse ftpRes = (System.Net.FtpWebResponse)ftpReq.GetResponse(); //FTPサーバーから送信されたステータスを表示 Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription); //閉じる ftpRes.Close();
FtpWebRequestのMethodプロパティにWebRequestMethods.Ftp.UploadFileWithUniqueNameを指定すると、"STOU"コマンドでファイルをアップロードすることができます。"STOR"コマンドと違い、FTPサーバーに同名のファイルが存在していても上書きはせずに、サーバーがユニークなファイル名をつけます。
方法は、上記の「FTPサーバーにファイルをアップロードする」と同じで、"WebRequestMethods.Ftp.UploadFile"を"WebRequestMethods.Ftp.UploadFileWithUniqueName"に変更するだけです。
補足:STOUコマンドをサポートしていないサーバーでは、FtpWebResponse.GetResponseメソッドを呼び出した時に、例外WebExceptionがスローされます。
FtpWebRequestのMethodプロパティにWebRequestMethods.Ftp.AppendFileを指定することにより、"APPE"コマンドでファイルをアップロードすることができます。この場合、FTPサーバーに同名のファイルが存在すると、そのファイルに追加書き込みで書き込まれます。同名のファイルが存在しないならば、新しくファイルが作成されます。
方法は、上記の「FTPサーバーにファイルをアップロードする」と同じで、"WebRequestMethods.Ftp.UploadFile"を"WebRequestMethods.Ftp.AppendFile"に変更するだけです。
FTPサーバーにあるディレクトリ内のファイル一覧を取得するには、FtpWebRequestのMethodプロパティにWebRequestMethods.Ftp.ListDirectoryまたはListDirectoryDetailsを指定します。ListDirectoryを指定した場合は、"NLIST"コマンドにより、簡単なファイルの一覧(ファイルとディレクトリ名が改行文字で区切られた文字列)が返されます。ListDirectoryDetailsを指定した場合は、"LIST"コマンドにより、より詳細なファイルの一覧(ファイルやディレクトリの属性、所有者、更新日時、サイズなどを含む)が返されます。
以下の例では、"LIST"コマンドで"ftp://localhost/"のファイル一覧を取得して、表示しています。
'ファイル一覧を取得するディレクトリのURI Dim u As New Uri("ftp://localhost/") 'FtpWebRequestの作成 Dim ftpReq As System.Net.FtpWebRequest = _ CType(System.Net.WebRequest.Create(u), System.Net.FtpWebRequest) 'ログインユーザー名とパスワードを設定 ftpReq.Credentials = New System.Net.NetworkCredential("username", "password") 'MethodにWebRequestMethods.Ftp.ListDirectoryDetails("LIST")を設定 ftpReq.Method = System.Net.WebRequestMethods.Ftp.ListDirectoryDetails '要求の完了後に接続を閉じる ftpReq.KeepAlive = False 'PASSIVEモードを無効にする ftpReq.UsePassive = False 'FtpWebResponseを取得 Dim ftpRes As System.Net.FtpWebResponse = _ CType(ftpReq.GetResponse(), System.Net.FtpWebResponse) 'FTPサーバーから送信されたデータを取得 Dim sr As New System.IO.StreamReader(ftpRes.GetResponseStream()) Dim res As String = sr.ReadToEnd() 'ファイル一覧を表示 Console.WriteLine(res) sr.Close() 'FTPサーバーから送信されたステータスを表示 Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription) '閉じる ftpRes.Close()
//ファイル一覧を取得するディレクトリのURI Uri u = new Uri("ftp://localhost/"); //FtpWebRequestの作成 System.Net.FtpWebRequest ftpReq = (System.Net.FtpWebRequest) System.Net.WebRequest.Create(u); //ログインユーザー名とパスワードを設定 ftpReq.Credentials = new System.Net.NetworkCredential("username", "password"); //MethodにWebRequestMethods.Ftp.ListDirectoryDetails("LIST")を設定 ftpReq.Method = System.Net.WebRequestMethods.Ftp.ListDirectoryDetails; //要求の完了後に接続を閉じる ftpReq.KeepAlive = false; //PASSIVEモードを無効にする ftpReq.UsePassive = false; //FtpWebResponseを取得 System.Net.FtpWebResponse ftpRes = (System.Net.FtpWebResponse)ftpReq.GetResponse(); //FTPサーバーから送信されたデータを取得 System.IO.StreamReader sr = new System.IO.StreamReader(ftpRes.GetResponseStream()); string res = sr.ReadToEnd(); //ファイル一覧を表示 Console.WriteLine(res); sr.Close(); //FTPサーバーから送信されたステータスを表示 Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription); //閉じる ftpRes.Close();
上記の例で日本語が文字化けする場合は、StreamReaderオブジェクトを作成するときに、適当なEncodingを指定してください。(FtpWebRequestはサーバーに接続後、"OPTS utf8 on"を送信していますので、サーバーがUTF-8をサポートしていれば、このままで問題ないでしょう。)
なお、このように"LIST"コマンドで取得したファイル一覧を解析する方法は、「Sample code for parsing FtpwebRequest response for ListDirectoryDetails」や「FTP のプロトコルの取得方法について」で紹介されています。
FTPサーバーにあるファイルの名前を変更するには、FtpWebRequestのMethodプロパティにWebRequestMethods.Ftp.Renameを指定します。このようにすると、"RNFR"と"RNTO"コマンドにより、ファイル名を変更します。変更後のファイル名は、FtpWebRequest.RenameToプロパティに設定しておきます。
以下の例では、"ftp://localhost/test.txt"のファイル名を"test2.txt"に変更しています。
'名前を変更するファイルのURI Dim u As New Uri("ftp://localhost/test.txt") '新しいファイル名 Dim newName As String = "test2.txt" 'FtpWebRequestの作成 Dim ftpReq As System.Net.FtpWebRequest = _ CType(System.Net.WebRequest.Create(u), System.Net.FtpWebRequest) 'ログインユーザー名とパスワードを設定 ftpReq.Credentials = New System.Net.NetworkCredential("username", "password") 'MethodにWebRequestMethods.Ftp.Rename(RENAME)を設定 ftpReq.Method = System.Net.WebRequestMethods.Ftp.Rename '変更後の新しいファイル名を設定 ftpReq.RenameTo = newName 'FtpWebResponseを取得 Dim ftpRes As System.Net.FtpWebResponse = _ CType(ftpReq.GetResponse(), System.Net.FtpWebResponse) 'FTPサーバーから送信されたステータスを表示 Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription) '閉じる ftpRes.Close()
//名前を変更するファイルのURI Uri u = new Uri("ftp://localhost/test.txt"); //新しいファイル名 string newName = "test2.txt"; //FtpWebRequestの作成 System.Net.FtpWebRequest ftpReq = (System.Net.FtpWebRequest) System.Net.WebRequest.Create(u); //ログインユーザー名とパスワードを設定 ftpReq.Credentials = new System.Net.NetworkCredential("username", "password"); //MethodにWebRequestMethods.Ftp.Rename(RENAME)を設定 ftpReq.Method = System.Net.WebRequestMethods.Ftp.Rename; //変更後の新しいファイル名を設定 ftpReq.RenameTo = newName; //FtpWebResponseを取得 System.Net.FtpWebResponse ftpRes = (System.Net.FtpWebResponse)ftpReq.GetResponse(); //FTPサーバーから送信されたステータスを表示 Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription); //閉じる ftpRes.Close();
"DELE"コマンドを送信してFTPサーバーにあるファイルを削除するには、FtpWebRequestのMethodプロパティにWebRequestMethods.Ftp.DeleteFileを指定します。"RMD"コマンドを送信してディレクトリを削除する時は、MethodプロパティにWebRequestMethods.Ftp.RemoveDirectoryを指定します。
以下の例では、"ftp://localhost/test.txt"を削除しています。
'削除するファイルのURI Dim u As New Uri("ftp://localhost/test.txt") 'FtpWebRequestの作成 Dim ftpReq As System.Net.FtpWebRequest = _ CType(System.Net.WebRequest.Create(u), System.Net.FtpWebRequest) 'ログインユーザー名とパスワードを設定 ftpReq.Credentials = New System.Net.NetworkCredential("username", "password") 'MethodにWebRequestMethods.Ftp.DeleteFile(DELE)を設定 ftpReq.Method = System.Net.WebRequestMethods.Ftp.DeleteFile 'FtpWebResponseを取得 Dim ftpRes As System.Net.FtpWebResponse = _ CType(ftpReq.GetResponse(), System.Net.FtpWebResponse) 'FTPサーバーから送信されたステータスを表示 Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription) '閉じる ftpRes.Close()
//削除するファイルのURI Uri u = new Uri("ftp://localhost/test.txt"); //FtpWebRequestの作成 System.Net.FtpWebRequest ftpReq = (System.Net.FtpWebRequest) System.Net.WebRequest.Create(u); //ログインユーザー名とパスワードを設定 ftpReq.Credentials = new System.Net.NetworkCredential("username", "password"); //MethodにWebRequestMethods.Ftp.DeleteFile(DELE)を設定 ftpReq.Method = System.Net.WebRequestMethods.Ftp.DeleteFile; //FtpWebResponseを取得 System.Net.FtpWebResponse ftpRes = (System.Net.FtpWebResponse)ftpReq.GetResponse(); //FTPサーバーから送信されたステータスを表示 Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription); //閉じる ftpRes.Close();
"MKD"コマンドを送信してFTPサーバーにディレクトリを作成するには、FtpWebRequestのMethodプロパティにWebRequestMethods.Ftp.MakeDirectoryを指定します。方法は、「FTPサーバーのファイルやディレクトリを削除する」と同じです。
"SIZE"コマンドを送信してFTPサーバーにあるファイルのサイズを取得するには、FtpWebRequestのMethodプロパティにWebRequestMethods.Ftp.GetFileSizeを指定します。取得したファイルサイズは、FtpWebResponse.ContentLengthプロパティに格納されます。
'サイズを取得するファイルのURI Dim u As New Uri("ftp://localhost/test.txt") 'FtpWebRequestの作成 Dim ftpReq As System.Net.FtpWebRequest = _ CType(System.Net.WebRequest.Create(u), System.Net.FtpWebRequest) 'ログインユーザー名とパスワードを設定 ftpReq.Credentials = New System.Net.NetworkCredential("username", "password") 'MethodにWebRequestMethods.Ftp.GetFileSize(SIZE)を設定 ftpReq.Method = System.Net.WebRequestMethods.Ftp.GetFileSize 'FtpWebResponseを取得 Dim ftpRes As System.Net.FtpWebResponse = _ CType(ftpReq.GetResponse(), System.Net.FtpWebResponse) '取得したファイルサイズを表示 Console.WriteLine(ftpRes.ContentLength) 'FTPサーバーから送信されたステータスを表示 Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription) '閉じる ftpRes.Close()
//サイズを取得するファイルのURI Uri u = new Uri("ftp://localhost/test.txt"); //FtpWebRequestの作成 System.Net.FtpWebRequest ftpReq = (System.Net.FtpWebRequest) System.Net.WebRequest.Create(u); //ログインユーザー名とパスワードを設定 ftpReq.Credentials = new System.Net.NetworkCredential("username", "password"); //MethodにWebRequestMethods.Ftp.GetFileSize(SIZE)を設定 ftpReq.Method = System.Net.WebRequestMethods.Ftp.GetFileSize; //FtpWebResponseを取得 System.Net.FtpWebResponse ftpRes = (System.Net.FtpWebResponse)ftpReq.GetResponse(); //取得したファイルサイズを表示 Console.WriteLine(ftpRes.ContentLength); //FTPサーバーから送信されたステータスを表示 Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription); //閉じる ftpRes.Close();
"MDTM"コマンドを送信してFTPサーバーにあるファイルの更新日時を取得するには、FtpWebRequestのMethodプロパティにWebRequestMethods.Ftp.GetDateTimestampを指定します。取得したファイルの更新日時は、FtpWebResponse.LastModifiedプロパティに格納されます。
'最終更新日時を取得するファイルのURI Dim u As New Uri("ftp://localhost/test.txt") 'FtpWebRequestの作成 Dim ftpReq As System.Net.FtpWebRequest = _ CType(System.Net.WebRequest.Create(u), System.Net.FtpWebRequest) 'ログインユーザー名とパスワードを設定 ftpReq.Credentials = New System.Net.NetworkCredential("username", "password") 'MethodにWebRequestMethods.Ftp.GetDateTimestamp(MDTM)を設定 ftpReq.Method = System.Net.WebRequestMethods.Ftp.GetDateTimestamp 'FtpWebResponseを取得 Dim ftpRes As System.Net.FtpWebResponse = _ CType(ftpReq.GetResponse(), System.Net.FtpWebResponse) '最終更新日時を表示 Console.WriteLine(ftpRes.LastModified) 'FTPサーバーから送信されたステータスを表示 Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription) '閉じる ftpRes.Close()
//最終更新日時を取得するファイルのURI Uri u = new Uri("ftp://localhost/test.txt"); //FtpWebRequestの作成 System.Net.FtpWebRequest ftpReq = (System.Net.FtpWebRequest) System.Net.WebRequest.Create(u); //ログインユーザー名とパスワードを設定 ftpReq.Credentials = new System.Net.NetworkCredential("username", "password"); //MethodにWebRequestMethods.Ftp.GetDateTimestamp(MDTM)を設定 ftpReq.Method = System.Net.WebRequestMethods.Ftp.GetDateTimestamp; //FtpWebResponseを取得 System.Net.FtpWebResponse ftpRes = (System.Net.FtpWebResponse)ftpReq.GetResponse(); //最終更新日時を表示 Console.WriteLine(ftpRes.LastModified); //FTPサーバーから送信されたステータスを表示 Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription); //閉じる ftpRes.Close();
"PWD"コマンドを送信してFTPサーバーのカレントディレクトリを取得するには、FtpWebRequestのMethodプロパティにWebRequestMethods.Ftp.PrintWorkingDirectoryを指定します。カレントディレクトリの情報は、FtpWebResponse.StatusDescriptionプロパティで取得できるメッセージ内に含まれます。方法は、「FTPサーバーのファイルやディレクトリを削除する」と同じですので、ここでは省略します。
FtpWebRequestのMethodプロパティには、WebRequestMethods.Ftpで定義されているパブリックフィールド以外の値は設定できません。よって、例えばSITEコマンドは送信できず、"SITE CHMOD"でファイルのパーミッション(属性)を変更することができません。
FtpWebRequestで送信することのできないコマンドをどうしても送信したい場合は、FtpWebRequestクラスを使用せずに、TcpClientやSocketクラスを使用してFTPサーバーに接続します。例えば、TcpClientクラスでFTPサーバーのファイルのパーミッションを変更するコードは、こちらなどで紹介されています。
補足:サードパーティーの無料(LGPL)のライブラリであるFree .NET FTP componentを使えば、SITEコマンドの送信が可能のようです。
例えば、FTPサーバーからファイル一覧を取得して、目的のファイルが存在すればそのファイルをダウンロードしたいといったケースは少なくありません。しかし、FtpWebRequestオブジェクトのMethodプロパティは、GetRequestStreamやGetResponseメソッドを呼び出した後には変更することができませんので、一つのFtpWebRequestオブジェクトを使って、あるコマンドを送信した後に別のコマンドを送信することができません。よって複数のコマンドを送信したい場合は、その数だけFtpWebRequestオブジェクトを作成する必要があります。
複数のFtpWebRequestオブジェクトを作成してコマンドを送信するとなると、それだけFTPサーバーとの接続と切断を繰り返すように思われるかもしれませんが、そうではありません。FtpWebRequestのKeepAliveプロパティがTrue(デフォルト)になっていれば、GetResponse.Closeメソッドが呼び出されてもFTPサーバーとの接続は切断されず、その後別のFtpWebRequestオブジェクトがその接続を利用することができます。デフォルトでKeepAliveプロパティはTrueです。
FTPサーバーから切断するときは、コマンドを送信するときにKeepAliveプロパティをFalseにします。
一つ例を示しましょう。以下のコードでは、Button1ボタンを押すと"ftp://localhost/doc"ディレクトリ内の".txt"ファイルをすべて削除しており、"Ftp.ListDirectory"を送信してから"Ftp.DeleteFile"を複数回送信しています。複数のFtpWebRequestオブジェクトを作成してコマンドを送信していますが、その間FTPサーバーにログインしたままログアウトすることなく、すべての作業が行われます。
さらにすべての作業終了後、DisconnectFtpメソッドを呼び出してFTPサーバーから切断しています。DisconnectFtpメソッドでは、KeepAliveプロパティをFalseにして"Ftp.PrintWorkingDirectory"コマンドを送信しています。切断するためにBYEコマンドだけ送信できればよいのですが、それができないため、仕方なくPrintWorkingDirectoryを送信しています。
Private ftpCredential As System.Net.NetworkCredential ''' <summary> ''' FTPサーバーからファイル一覧を取得する ''' </summary> ''' <param name="dirUri">ディレクトリのURI</param> ''' <returns>ファイル、ディレクトリ名の一覧</returns> Private Function GetFtpDirectoryList(ByVal dirUri As String) As String() Dim ftpReq As System.Net.FtpWebRequest = _ DirectCast(System.Net.WebRequest.Create(dirUri), System.Net.FtpWebRequest) If Me.ftpCredential IsNot Nothing Then ftpReq.Credentials = Me.ftpCredential End If ftpReq.Method = System.Net.WebRequestMethods.Ftp.ListDirectory ftpReq.UsePassive = False Dim dirList As New System.Collections.Generic.List(Of String)() Using ftpRes As System.Net.FtpWebResponse = _ DirectCast(ftpReq.GetResponse(), System.Net.FtpWebResponse) Using sr As New System.IO.StreamReader(ftpRes.GetResponseStream()) While True Dim line As String = sr.ReadLine() If line Is Nothing Then Exit While End If dirList.Add(line) End While End Using End Using Return dirList.ToArray() End Function ''' <summary> ''' FTPサーバーのファイルを削除する ''' </summary> ''' <param name="fileUri">削除するファイルのURI</param> Private Sub DeleteFtpFile(ByVal fileUri As String) Dim ftpReq As System.Net.FtpWebRequest = _ DirectCast(System.Net.WebRequest.Create(fileUri), System.Net.FtpWebRequest) If Me.ftpCredential IsNot Nothing Then ftpReq.Credentials = Me.ftpCredential End If ftpReq.Method = System.Net.WebRequestMethods.Ftp.DeleteFile Using ftpRes As System.Net.FtpWebResponse = _ DirectCast(ftpReq.GetResponse(), System.Net.FtpWebResponse) End Using End Sub ''' <summary> ''' FTPサーバーから切断する ''' </summary> ''' <param name="uri">切断するFTPサーバーのURI</param> Private Sub DisconnectFtp(ByVal uri As String) Dim ftpReq As System.Net.FtpWebRequest = _ DirectCast(System.Net.WebRequest.Create(uri), System.Net.FtpWebRequest) If Me.ftpCredential IsNot Nothing Then ftpReq.Credentials = Me.ftpCredential End If ftpReq.Method = System.Net.WebRequestMethods.Ftp.PrintWorkingDirectory ftpReq.KeepAlive = False Using ftpRes As System.Net.FtpWebResponse = _ DirectCast(ftpReq.GetResponse(), System.Net.FtpWebResponse) End Using End Sub 'Button1のClickイベントハンドラ Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) _ Handles Button1.Click Me.ftpCredential = New System.Net.NetworkCredential("username", "password") Dim dirList As String() = Me.GetFtpDirectoryList("ftp://localhost/doc/") Dim fn As String For Each fn In dirList If fn.EndsWith(".txt", StringComparison.CurrentCultureIgnoreCase) Then Me.DeleteFtpFile(("ftp://localhost/doc/" + fn)) End If Next fn Me.DisconnectFtp("ftp://localhost") End Sub
private System.Net.NetworkCredential ftpCredential; /// <summary> /// FTPサーバーからファイル一覧を取得する /// </summary> /// <param name="dirUri">ディレクトリのURI</param> /// <returns>ファイル、ディレクトリ名の一覧</returns> private string[] GetFtpDirectoryList(string dirUri) { System.Net.FtpWebRequest ftpReq = (System.Net.FtpWebRequest) System.Net.WebRequest.Create(dirUri); if (this.ftpCredential != null) ftpReq.Credentials = this.ftpCredential; ftpReq.Method = System.Net.WebRequestMethods.Ftp.ListDirectory; ftpReq.UsePassive = false; System.Collections.Generic.List<string> dirList = new System.Collections.Generic.List<string>(); using (System.Net.FtpWebResponse ftpRes = (System.Net.FtpWebResponse)ftpReq.GetResponse()) using (System.IO.StreamReader sr = new System.IO.StreamReader(ftpRes.GetResponseStream())) { while (true) { string line = sr.ReadLine(); if (line == null) break; dirList.Add(line); } } return dirList.ToArray(); } /// <summary> /// FTPサーバーのファイルを削除する /// </summary> /// <param name="fileUri">削除するファイルのURI</param> private void DeleteFtpFile(string fileUri) { System.Net.FtpWebRequest ftpReq = (System.Net.FtpWebRequest) System.Net.WebRequest.Create(fileUri); if (this.ftpCredential != null) ftpReq.Credentials = this.ftpCredential; ftpReq.Method = System.Net.WebRequestMethods.Ftp.DeleteFile; using (System.Net.FtpWebResponse ftpRes = (System.Net.FtpWebResponse)ftpReq.GetResponse()) { } } /// <summary> /// FTPサーバーから切断する /// </summary> /// <param name="uri">切断するFTPサーバーのURI</param> private void DisconnectFtp(string uri) { System.Net.FtpWebRequest ftpReq = (System.Net.FtpWebRequest) System.Net.WebRequest.Create(uri); if (this.ftpCredential != null) ftpReq.Credentials = this.ftpCredential; ftpReq.Method = System.Net.WebRequestMethods.Ftp.PrintWorkingDirectory; ftpReq.KeepAlive = false; using (System.Net.FtpWebResponse ftpRes = (System.Net.FtpWebResponse)ftpReq.GetResponse()) { } } //Button1のClickイベントハンドラ private void Button1_Click(object sender, EventArgs e) { this.ftpCredential = new System.Net.NetworkCredential("username", "password"); string[] dirList = this.GetFtpDirectoryList("ftp://localhost/doc/"); foreach (string fn in dirList) { if (fn.EndsWith(".txt", StringComparison.CurrentCultureIgnoreCase)) { this.DeleteFtpFile("ftp://localhost/doc/" + fn); } } this.DisconnectFtp("ftp://localhost"); }
このコードを実行したときに、具体的にFTPサーバーとどのようなやりとりが行われるかの例を以下に示します。これは、FTPサーバーとしてnekosogiFTPを使用した時に出力されたログを一部編集したものです。
>>220 Enter Your ID >>USER username <<331 Enter Your Password >>PASS password <<230 Login OK!!! >>OPTS utf8 on <<502 Command not implemented. >>PWD <<257 "/" is your directory. >>CWD /doc/ <<250 Requested file action okay, completed. >>TYPE I <<200 Binary Mode >>PORT 127,0,0,1,7,37 <<200 PORT command successful. >>NLST <<150 Opening data connection. <<226 Transfer complete. >>DELE 1.txt <<250 Requested file action okay, completed. >>DELE 2.txt <<250 Requested file action okay, completed. >>DELE 3.txt <<250 Requested file action okay, completed. >>CWD // <<250 Requested file action okay, completed. >>PWD <<257 "/" is your directory. >>QUIT <<221 Good-Bye
例外がスローされてうまくいかないときは、まずスローされた例外の内容を確認してください。もしスローされた例外がWebExceptionであれば、WebExceptionのStatusDescriptionプロパティで最後にサーバーが返したステータスコードを確認できます。
例えば下図のような「WebExceptionはハンドルされませんでした。」というウィンドウが表示されたとします。
ここで「アクション」の「詳細の表示...」をクリックすると、以下のようなダイアログが表示されて、WebExceptionの中身を確認できます。
それでも原因が分からないときは、ネットワークトレースを行い、サーバーとのやり取りを確認してみてください。ネットワークトレースについては、「ネットワークのトレースを行う」をご覧ください。