none
How to match certain directory name RRS feed

  • 質問

  • I wrote a code to examine directories.
    I want to skip certain directory using regex.

    I wrote

     string inputString = d;
                        string pattern = @".*\\AppData\\Local\\Application Data\\.*";
                        Match match = Regex.Match(inputString, pattern, RegexOptions.Multiline);
                        if (match.Success)
                        {
                            continue;
                        }else{
                            ....
                        }

    but seems not working. What's wrong?

                       

    2009年11月23日 12:10

回答

  • totojo さん、正規表現パターン内のバックスラッシュのエスケープなので、2つ重ねるのは正しいと思います。

    正規表現での処理に問題はなさそうに思いました。
    (固定値になっていると OS が変わった時に問題が起きるかもしれないですけど)
    intrajp さんの期待通りにならないのはなぜでしょうね。
    別の箇所に問題はないでしょうか?

    本題からそれてしまいますが、別の方法を考えました。
    Application Data などのアクセスできないフォルダは「JUNCTION」と言うものだそうです。

    「Error message when you try to access the My Documents, My Music, My Pictures, and My Videos folders in Windows Vista: "Access is Denied"」
    http://support.microsoft.com/kb/930128/en

    ジャンクションの厳密な判定方法はわかりませんでしたが、とりあえず以下のように判定できそうです。
    このように除外されてはいかがでしょうか?

    string path = @"C:\Users\Default\AppData\Local";
    foreach (string dir in Directory.GetDirectories(path))
    {
        DirectoryInfo di = new DirectoryInfo(dir);
        if (!di.Exists) continue;

        FileAttributes attributes =
            FileAttributes.System | FileAttributes.Hidden | FileAttributes.ReparsePoint;
        bool maybeJunction = (di.Attributes & attributes) == attributes;
        if (maybeJunction) continue;

        // 処理
    }

    一応、元スレッドにリンクしておきますね。
    「ファイル検索プログラム作成でアクセス拒否」
    http://social.msdn.microsoft.com/Forums/ja-JP/csharpexpressja/thread/d7e23abf-7892-4322-8202-4ce66f90f5e3

    • 回答の候補に設定 Jitta 2009年12月1日 13:46
    • 回答としてマーク 高橋 春樹 2009年12月8日 9:36
    2009年11月24日 10:32
  • # 英語は書けないので、そのまま日本語で書きます。

    逐語的リテラル文字列 (Verbatim String) はエスケープされないので、これが原因ではないでしょうか?
    "pattern" のパスの区切りで、バックスラッシュが2個ずつ入ってしまいます。

     文字列の基本 (C# プログラミング ガイド)
     http://msdn.microsoft.com/ja-jp/library/ms228362.aspx
     (参照: 標準リテラル文字列と逐語的リテラル文字列)

     String Basics (C# Programming Guide)
     http://msdn.microsoft.com/en-us/library/ms228362.aspx
     (See: Regular and Verbatim String Literals)

    string pattern = @".*\\AppData\\Local\\Application Data\\.*";



    string pattern = @".*\AppData\Local\Application Data\.*";

    とすると、どうでしょうか?
    2009年11月24日 5:28
  • totojo さん、正規表現パターン内のバックスラッシュのエスケープなので、2つ重ねるのは正しいと思います

    おっと、そういえばそうですね。前スレッドは忘れてください。
    そうすると、inputString に渡しているディレクトリ名がフルパスでないとか...。

    あと、この正規表現パターンだと「Application Data」で終わるディレクトリ自体はスキップできないのですが、それはいいものでしょうか?
    2009年11月24日 11:00
  • そうすると、inputString に渡しているディレクトリ名がフルパスでないとか...。

    「@".*\\AppData\\Local\\Application Data\\.*";」なので、"C:\Temp\Backup\AppData\Local\Applocation Data\ABC" も、対象になっちゃうとか。

    マルチラインを指定しているので、その辺が悪さしているとか。

    それと、終わりの ".*" は、いらないと思います。


    Application Data などのアクセスできないフォルダは「JUNCTION」と言うものだそうです。

    一応、元スレッドの方に書いているんだけどね。


    Jitta@わんくま同盟
    2009年11月24日 13:26
  • 私は問題なさそうと書きましたが、totojo さんが指摘されているように、最後のバックスラッシュはいらなさそうですね。

    Jitta さん
    > それと、終わりの ".*" は、いらないと思います。
    親フォルダが対象外になれば、子フォルダの判定は不要ということですね。

    「問題ない」と書いて問題があれば迷惑になるのでよく見直してたのですが、気づきませんでした。

    お二人のを合わせると、
    string pattern = @".*\\AppData\\Local\\Application Data";
    で良いことになります。
    もしバックスラッシュの有無に依存せず、子フォルダまでも判定する場合は次のパターンになります。
    string pattern = @".*\\AppData\\Local\\Application Data(\\?|\\.*)";

    1つ目のパターンで良い場合、正規表現は使わずに
    if ((inputString ?? "").EndsWith(@"\AppData\Local\Application Data")) continue;
    という判定でも良さそうです。

    Jitta さん
    > 一応、元スレッドの方に書いているんだけどね。
    読みのがしてました。。

    • 編集済み TH01 2009年11月25日 0:55 if文が違ってたので修正
    • 回答としてマーク 高橋 春樹 2009年12月8日 9:36
    2009年11月25日 0:43
  • > 一応、元スレッドの方に書いているんだけどね。

    読みのがしてました。。

    誤解させたようで、ごめんなさい。TH01さんに対して何か言っているわけではありません。「何故アクセスできないか」について、原因を書いているのに、その原因を吟味していない質問者さんに対しての苦言です。


    string pattern = @".*\\AppData\\Local\\Application Data";
    で良いことになります。

    string pattern = @"[a-zA-Z]:\\AppData\\Local\\Application Data";”かと。先に書いたように、".*" だと「任意の文字が任意の数」です。元スレッドを合わせると、ここはドライブ ルートからのパスだと思います。



    面倒なのでこっちにくっつけときます。

    あと、もしシステムフォルダも検索するとしたら、方法はないのでしょうか?

    Windows Service にして、LOCAL SYSTEM で動かせば可能かと思います。

    しかし、SYSTEM にしか書き込みできないところに、任意のユーザーが書き込みすることは出来ない=そんなところにファイルはない(あってもシャドー コピー)と思います。


    Jitta@わんくま同盟
    2009年11月25日 13:21

すべての返信

  • # 英語は書けないので、そのまま日本語で書きます。

    逐語的リテラル文字列 (Verbatim String) はエスケープされないので、これが原因ではないでしょうか?
    "pattern" のパスの区切りで、バックスラッシュが2個ずつ入ってしまいます。

     文字列の基本 (C# プログラミング ガイド)
     http://msdn.microsoft.com/ja-jp/library/ms228362.aspx
     (参照: 標準リテラル文字列と逐語的リテラル文字列)

     String Basics (C# Programming Guide)
     http://msdn.microsoft.com/en-us/library/ms228362.aspx
     (See: Regular and Verbatim String Literals)

    string pattern = @".*\\AppData\\Local\\Application Data\\.*";



    string pattern = @".*\AppData\Local\Application Data\.*";

    とすると、どうでしょうか?
    2009年11月24日 5:28
  • totojo さん、正規表現パターン内のバックスラッシュのエスケープなので、2つ重ねるのは正しいと思います。

    正規表現での処理に問題はなさそうに思いました。
    (固定値になっていると OS が変わった時に問題が起きるかもしれないですけど)
    intrajp さんの期待通りにならないのはなぜでしょうね。
    別の箇所に問題はないでしょうか?

    本題からそれてしまいますが、別の方法を考えました。
    Application Data などのアクセスできないフォルダは「JUNCTION」と言うものだそうです。

    「Error message when you try to access the My Documents, My Music, My Pictures, and My Videos folders in Windows Vista: "Access is Denied"」
    http://support.microsoft.com/kb/930128/en

    ジャンクションの厳密な判定方法はわかりませんでしたが、とりあえず以下のように判定できそうです。
    このように除外されてはいかがでしょうか?

    string path = @"C:\Users\Default\AppData\Local";
    foreach (string dir in Directory.GetDirectories(path))
    {
        DirectoryInfo di = new DirectoryInfo(dir);
        if (!di.Exists) continue;

        FileAttributes attributes =
            FileAttributes.System | FileAttributes.Hidden | FileAttributes.ReparsePoint;
        bool maybeJunction = (di.Attributes & attributes) == attributes;
        if (maybeJunction) continue;

        // 処理
    }

    一応、元スレッドにリンクしておきますね。
    「ファイル検索プログラム作成でアクセス拒否」
    http://social.msdn.microsoft.com/Forums/ja-JP/csharpexpressja/thread/d7e23abf-7892-4322-8202-4ce66f90f5e3

    • 回答の候補に設定 Jitta 2009年12月1日 13:46
    • 回答としてマーク 高橋 春樹 2009年12月8日 9:36
    2009年11月24日 10:32
  • totojo さん、正規表現パターン内のバックスラッシュのエスケープなので、2つ重ねるのは正しいと思います

    おっと、そういえばそうですね。前スレッドは忘れてください。
    そうすると、inputString に渡しているディレクトリ名がフルパスでないとか...。

    あと、この正規表現パターンだと「Application Data」で終わるディレクトリ自体はスキップできないのですが、それはいいものでしょうか?
    2009年11月24日 11:00
  • そうすると、inputString に渡しているディレクトリ名がフルパスでないとか...。

    「@".*\\AppData\\Local\\Application Data\\.*";」なので、"C:\Temp\Backup\AppData\Local\Applocation Data\ABC" も、対象になっちゃうとか。

    マルチラインを指定しているので、その辺が悪さしているとか。

    それと、終わりの ".*" は、いらないと思います。


    Application Data などのアクセスできないフォルダは「JUNCTION」と言うものだそうです。

    一応、元スレッドの方に書いているんだけどね。


    Jitta@わんくま同盟
    2009年11月24日 13:26
  • 私は問題なさそうと書きましたが、totojo さんが指摘されているように、最後のバックスラッシュはいらなさそうですね。

    Jitta さん
    > それと、終わりの ".*" は、いらないと思います。
    親フォルダが対象外になれば、子フォルダの判定は不要ということですね。

    「問題ない」と書いて問題があれば迷惑になるのでよく見直してたのですが、気づきませんでした。

    お二人のを合わせると、
    string pattern = @".*\\AppData\\Local\\Application Data";
    で良いことになります。
    もしバックスラッシュの有無に依存せず、子フォルダまでも判定する場合は次のパターンになります。
    string pattern = @".*\\AppData\\Local\\Application Data(\\?|\\.*)";

    1つ目のパターンで良い場合、正規表現は使わずに
    if ((inputString ?? "").EndsWith(@"\AppData\Local\Application Data")) continue;
    という判定でも良さそうです。

    Jitta さん
    > 一応、元スレッドの方に書いているんだけどね。
    読みのがしてました。。

    • 編集済み TH01 2009年11月25日 0:55 if文が違ってたので修正
    • 回答としてマーク 高橋 春樹 2009年12月8日 9:36
    2009年11月25日 0:43
  • > 一応、元スレッドの方に書いているんだけどね。

    読みのがしてました。。

    誤解させたようで、ごめんなさい。TH01さんに対して何か言っているわけではありません。「何故アクセスできないか」について、原因を書いているのに、その原因を吟味していない質問者さんに対しての苦言です。


    string pattern = @".*\\AppData\\Local\\Application Data";
    で良いことになります。

    string pattern = @"[a-zA-Z]:\\AppData\\Local\\Application Data";”かと。先に書いたように、".*" だと「任意の文字が任意の数」です。元スレッドを合わせると、ここはドライブ ルートからのパスだと思います。



    面倒なのでこっちにくっつけときます。

    あと、もしシステムフォルダも検索するとしたら、方法はないのでしょうか?

    Windows Service にして、LOCAL SYSTEM で動かせば可能かと思います。

    しかし、SYSTEM にしか書き込みできないところに、任意のユーザーが書き込みすることは出来ない=そんなところにファイルはない(あってもシャドー コピー)と思います。


    Jitta@わんくま同盟
    2009年11月25日 13:21
  • みなさん、どうもすみません。

    windowsプログラムを書くのが初めてなので、アクセスできないというのがどうも納得できていませんでした。

    元スレッドの方に皆さんに教えていただいて自分で解決策と思えるコードを出しました。

    これでできたと思っています。

    ありがとうでした。
    2009年11月29日 10:54
  • フォーラムオペレーターの高橋春樹です。

    totojoさん、TH01さん、Jittaさん、こんにちは。
    アドバイスありがとうございました。

    intrajpさん、こんにちは。
    MSDNフォーラムのご利用ありがとうございます。

    皆さんからのアドバイスが、疑問点の解決に繋がったようで、よかったです。
    今回、totojoさん、TH01さん、Jittaさんからの投稿が、有用な情報だと思いましたので、
    勝手ながら、こちらで回答マークを付けさせてもらいました。
    次回からでよいのですが、疑問点が解決した場合、お礼も兼ねて参考になったと思われる投稿に、
    回答マークを付けて貰いたいと思います。

    今後ともMSDNフォーラムをよろしくお願いします(^_^)


    マイクロソフト株式会社 フォーラム オペレーター 高橋春樹
    2009年12月8日 9:37