.NET TIPS

FTP時にディレクトリの存在を調べるには?[2.0、C#、VB]

デジタルアドバンテージ 遠藤 孝信
2008/07/03

 「TIPS:WebClientクラスでFTPによりファイル転送を行うには?」や「TIPS:WebRequest/WebResponseクラスでFTPによりファイル転送を行うには?」では、FTPによるファイルのアップロード方法について解説しているが、ローカルPC上のディレクトリ構成に従ってファイルをアップロードするような場合には、FTPサーバ上でのディレクトリの作成が必要となることがある。

 例えば、FTP先のURLが、

ftp://servername/foo/bar/myfile.txt
(=FTPサーバservername上のディレクトリ/far/bar内のファイルmyfile.txt)

となるようにファイルをアップロードするには、FTPサーバ上に/fooディレクトリと、/foo/barディレクトリが存在していなければならず、もしなければ事前にディレクトリを作成しておく必要がある。本稿では、このようなURLにより指定されたFTPサーバ上のディレクトリの存在チェック方法について解説する。

ディレクトリ内のリスティング

 FTPによるファイル操作はローカルPC上でのそれと比べると非常に限られているが、ファイルやディレクトリの確認に関しては、指定したディレクトリ内の一覧が可能だ。このためのコードは次のようになる。

using System;
using System.Net;
using System.IO;

……中略……

WebRequest req = WebRequest.Create("ftp://servername/foo/");
req.Credentials = new NetworkCredential("user01", "mypassword");
req.Method = WebRequestMethods.Ftp.ListDirectory;

string output = "";
using (WebResponse res = req.GetResponse())
using (StreamReader sr = new StreamReader(res.GetResponseStream())) {
  output = sr.ReadToEnd();
}
Console.WriteLine(output);
Imports System
Imports System.Net
Imports System.IO

……中略……

Dim req As WebRequest = WebRequest.Create("ftp://servername/foo/")
req.Credentials = New NetworkCredential("user01", "mypassword")
req.Method = WebRequestMethods.Ftp.ListDirectory

Dim output As String = ""
Using res As WebResponse = req.GetResponse()
  Using sr As New StreamReader(res.GetResponseStream())
    output = sr.ReadToEnd()
  End Using
End Using
Console.WriteLine(output)
/fooディレクトリ内の一覧を取得するコード(上:C#、下:VB)

 このコードは、FTPサーバ上に/fooディレクトリが存在すれば一覧を文字列として取得できるが、もし/fooディレクトリが存在しなければ例外が発生する。従って、例外が発生するかどうかでディレクトリの存在をチェックすることができる。

 ただし、サーバに接続できない、認証情報が正しくないなど、ほかにも例外が発生する要因は数多くあるため、ディレクトリのアクセスに関する例外であることを確認する必要がある。これについて次に述べる。

ディレクトリにアクセスできなかった場合の状態

 ディレクトリにアクセスしようとしたが存在せずにアクセスできなかったというエラーは、FTPプロトコルにおけるエラーである。このようなエラーが発生した場合には、まず、WebExceptionオブジェクト(System.Net名前空間)のStatusプロパティに「WebExceptionStatus.ProtocolError」がセットされる。WebExceptionオブジェクトは、WebResponseクラス(System.Net名前空間)のGetResponseメソッドを呼び出したときにスローされる例外だ。

 この場合には、FTPサーバとのアクセスには問題がないため、FTPサーバからの応答を取得することができる。この応答はWebExceptionオブジェクトのResponseプロパティから、FtpWebResponseオブジェクト(System.Net名前空間)として取得できる。そして、ディレクトリにアクセスできなかった場合には、応答のステータスを示すFtpWebResponseオブジェクトのStatusCodeプロパティが「FtpStatusCode.ActionNotTakenFileUnavailable」となる。

 ディレクトリにアクセスして以上のような状態となった場合には、ディレクトリは存在しないと見なしてよいだろう。これらをコードにまとめると、以下のサンプル・プログラム中のdirExistsメソッドのようになる。

// ftpdirexists.cs

using System;
using System.Net;

class FTPHelper {

  static void Main() {
    NetworkCredential cred
        = new NetworkCredential("user01", "mypassword");
    string dirUri = "ftp://servername/foo/";
    Console.WriteLine(dirExists(cred, dirUri));
  }

  static bool dirExists(NetworkCredential cred, string uri) {
    WebRequest req = WebRequest.Create(uri);
    req.Proxy = null; // 接続の高速化
    req.Credentials = cred;
    req.Method = WebRequestMethods.Ftp.ListDirectory;;

    WebResponse res = null;
    try {
      res = req.GetResponse();
    } catch (WebException e) {
      if (e.Status == WebExceptionStatus.ProtocolError) {
        FtpWebResponse r = (FtpWebResponse)e.Response;
        if (r.StatusCode ==
                FtpStatusCode.ActionNotTakenFileUnavailable) {
          return false;
        }
      }
      throw; // ファイル関連以外の例外は再スロー
    } finally {
      if (res != null) {
        res.Close();
      }
    }
    return true;
  }
}

// コンパイル方法:csc ftpdirexists.cs
FTPでディレクトリの存在を調べるC#のサンプル・プログラム(ftpdirexists.cs)

' ftpdirexists.vb

Imports System
Imports System.Net

Class FTPHelper
  Shared Sub Main()
    Dim cred As New NetworkCredential("user01", "mypassword")
    Dim dirUri As String = "ftp://servername/foo/"
    Console.WriteLine(dirExists(cred, dirUri))
  End Sub

  Shared Function dirExists(ByVal cred As NetworkCredential, ByVal uri As String) As Boolean
    Dim req As WebRequest = WebRequest.Create(uri)
    req.Proxy = Nothing ' 接続の高速化
    req.Credentials = cred
    req.Method = WebRequestMethods.Ftp.ListDirectory

    Dim res As WebResponse = Nothing
    Try
      res = req.GetResponse()
    Catch e As WebException
      If e.Status = WebExceptionStatus.ProtocolError Then
        Dim r As FtpWebResponse = CType(e.Response, FtpWebResponse)
        If r.StatusCode = _
                FtpStatusCode.ActionNotTakenFileUnavailable Then
          Return False
        End If
      End If
      Throw ' ファイル関連以外の例外は再スロー
    Finally
      If Not res Is Nothing Then
        res.Close()
      End If
    End Try
    Return True
  End Function
End Class

' コンパイル方法:vbc ftpdirexists.vb
FTPでディレクトリの存在を調べるVBのサンプル・プログラム(ftpdirexists.vb)

 なお、ディレクトリを指すURL(上記のコードでは「ftp://servername/foo/」)の最後のスラッシュ(/)には注意が必要だ。/fooディレクトリが存在しない場合、この最後のスラッシュがないと、「foo」という名前のファイルについてアクセスすることになるためである(サーバによっては、fooというファイルが存在しなくても例外が発生しない)。End of Article

利用可能バージョン:.NET Framework 2.0以降
カテゴリ:クラス・ライブラリ 処理対象:ネットワーク
使用ライブラリ:WebExceptionオブジェクト(System.Net名前空間)
使用ライブラリ:WebResponseクラス(System.Net名前空間)
使用ライブラリ:FtpWebResponseオブジェクト(System.Net名前空間)
関連TIPS:WebClientクラスでFTPによりファイル転送を行うには?
関連TIPS:WebRequest/WebResponseクラスでFTPによりファイル転送を行うには?

この記事と関連性の高い別の.NET TIPS
FTPでエラーが発生した場合に生のメッセージを取得するには?
WebClientクラスでFTPによりファイル転送を行うには?
WebRequest/WebResponseクラスでFTPによりファイル転送を行うには?
ディレクトリを作成/削除/リネーム/移動するには?
ファイルやディレクトリの一覧を取得するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間