web-dev-qa-db-ja.com

WebRequestMethods.Ftp.ListDirectoryDe​​tails FTP応答を解析するためのC#クラス

FTPの場所で新しい更新を監視するサービスを作成しており、WebRequestMethods.Ftp.ListDirectoryDe​​tailsメソッドを使用してFtpWebRequest応答から返された応答を解析する機能が必要です。すべての応答が同じ形式に従っている場合はかなり簡単ですが、FTPサーバーソフトウェアが異なれば、応答形式も異なります。

たとえば、次のようになります。

08-10-11  12:02PM       <DIR>          Version2
06-25-09  02:41PM            144700153 image34.gif
06-25-09  02:51PM            144700153 updates.txt
11-04-10  02:45PM            144700214 digger.tif

そして、別のサーバーが戻る可能性があります。

d--x--x--x    2 ftp      ftp          4096 Mar 07  2002 bin
-rw-r--r--    1 ftp      ftp        659450 Jun 15 05:07 TEST.TXT
-rw-r--r--    1 ftp      ftp      101786380 Sep 08  2008 TEST03-05.TXT
drwxrwxr-x    2 ftp      ftp          4096 May 06 12:24 dropoff

また、他の違いも観察されているので、まだ遭遇していない微妙な違いがいくつかある可能性があります。

これらの状況をシームレスに処理するフルマネージド(Windowsでは外部dllへのアクセスを必要としない)C#クラスを知っている人はいますか?

次の詳細を含むディレクトリの内容をリストするだけで済みます:ファイル/ディレクトリ名、最終更新または作成されたタイムスタンプ、ファイル/ディレクトリ名。

提案を事前にありがとう、ギャビン

20
Gavin

私が遭遇した1つの解決策は EdtFTPnet

EdtFTPnetは、さまざまなFTPオプションを処理する機能満載のソリューションのようであるため、理想的です。

これは私がどのように採用したかという無料のオープンソースソリューションです http://www.ftp2rss.com (私が自分で必要としていたが、他の人にも役立つかもしれないと考えた小さなツール)。

4
Gavin

最初の(DOS/Windows)リストでは、このコードは次のことを行います。

FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftp.example.com/");
request.Credentials = new NetworkCredential("user", "password");
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream());

string pattern = @"^(\d+-\d+-\d+\s+\d+:\d+(?:AM|PM))\s+(<DIR>|\d+)\s+(.+)$";
Regex regex = new Regex(pattern);
IFormatProvider culture = CultureInfo.GetCultureInfo("en-us");
while (!reader.EndOfStream)
{
    string line = reader.ReadLine();
    Match match = regex.Match(line);
    DateTime modified =
       DateTime.ParseExact(
           match.Groups[1].Value, "MM-dd-yy  hh:mmtt", culture, DateTimeStyles.None);
    long size = (match.Groups[2].Value != "<DIR>") ? long.Parse(match.Groups[2].Value) : 0;
    string name = match.Groups[3].Value;

    Console.WriteLine(
        "{0,-16} size = {1,9}  modified = {2}",
        name, size, modified.ToString("yyyy-MM-dd HH:mm"));
}

あなたが得るでしょう:

Version2         size =         0  modified = 2011-08-10 12:02
image34.gif      size = 144700153  modified = 2009-06-25 14:41
updates.txt      size = 144700153  modified = 2009-06-25 14:51
digger.tif       size = 144700214  modified = 2010-11-04 14:45

他の(* nix)リストについては、 FtpWebRequest ListDirectoryDe​​tails行の解析に対する私の回答 を参照してください。


しかし、実際にListDirectoryDetailsによって返されたリストを解析しようとすることは、正しい方法ではありません。

RFC 3659 で指定された機械可読形式でディレクトリリストを返す最新のMLSDコマンドをサポートするFTPクライアントを使用するとします。古代のLISTコマンド(FtpWebRequestメソッドのListDirectoryDetailsによって内部的に使用される)によって返される人間が読める形式を解析することは、通信するときの最後の手段として使用する必要があります。 MLSDコマンドをサポートしない廃止されたFTPサーバー(Microsoft IIS FTPサーバーなど)。


たとえば、 WinSCP .NET Assembly の場合、その Session.ListDirectory または Session.EnumerateRemoteFiles メソッド。

内部的にはMLSDコマンドを使用しますが、LISTコマンドにフォールバックして、人間が読める形式の数十の異なるリスト形式をサポートできます。

返されるリストは、次のようなプロパティを持つ RemoteFileInfoインスタンス のコレクションとして表示されます。

  • Name
  • LastWriteTime(正しいタイムゾーンで)
  • Length
  • FilePermissions(個人の権利に解析されます)
  • Group
  • Owner
  • IsDirectory
  • IsParentDirectory
  • IsThisDirectory

(私はWinSCPの作者です)


他のほとんどのサードパーティライブラリも同じことをします。 FtpWebRequest class の使用は、この目的では信頼できません。残念ながら、.NETFrameworkには他に組み込みのFTPクライアントはありません。

9
Martin Prikryl

私はこれと同じ問題に直面しており、正規表現を使用して単純な(それほど堅牢ではありませんが)ソリューションを構築し、キャプチャグループを使用して各行から関連情報を解析しました。

public static Regex FtpListDirectoryDetailsRegex = new Regex(@".*(?<month>(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))\s*(?<day>[0-9]*)\s*(?<yearTime>([0-9]|:)*)\s*(?<fileName>.*)", RegexOptions.Compiled | RegexOptions.IgnoreCase);

次に、次の方法でキャプチャグループから値を抽出できます。

        string ftpResponse = "-r--r--r-- 1 ftp ftp              0 Nov 19 11:08 aaa.txt";
        Match match = FtpListDirectoryDetailsRegex.Match(ftpResponse);
        string month = match.Groups["month"].Value;
        string day = match.Groups["day"].Value;
        string yearTime = match.Groups["yearTime"].Value;
        string fileName = match.Groups["fileName"].Value;

注意しない点は次のとおりです。

  • これは、上記のftpResponse変数に記載されている形式のディレクトリ応答に対してのみ機能します。私の場合、毎回同じFTPサーバーにしかアクセスできないので、応答形式が変わる可能性はほとんどありません。
  • yearTime変数は、ファイルのタイムスタンプの年または時刻のいずれかを表すことができます。このキャプチャグループに年ではなく時間が含まれていることを示すコロン:文字のインスタンスを探して、これを手動で解析する必要があります。
7
calturk

Ftp.dll FTPクライアント を見てください。

これには、Windows、Unix、およびNetwareプラットフォーム上のほとんどのFTPサーバー用の 自動ディレクトリリストパーサー が含まれます。

これは私が開発した商用製品であることに注意してください。

0