none
複数条件で比較をしたい RRS feed

  • 質問

  • 現在、C#を勉強していてデスクトップ上のファイルを自動的に整理するアプリを作成したいと考えています。

    そこで、デスクトップ上のPDFファイルを特定のフォルダに移動させたのですがいくつかのファイルはデスクトップ上に

    残しておきたいファイルが有ったので例外を儲けたいと思っています。

    自分だけの環境であればIFを何回か比較させれば良いのですが、最終的にはフリーソフトで皆さんに使って頂ければ・・・

    っと思っているのでユーザー毎に何個の例外ファイルを指定してくるか解らないので複数条件で対応させたいと考えています。

    C#の書式的には間違ってるかもですが、私のイメージ的には下記のようなイメージです。

    IF(例外ファイル名=現在ファイル名);

    例外ファイル名は、複数のファイル名が格納されていて

    現在のファイル名は1つだけのファイル名で、比較してなければ移動処理

    例外ファイル名とイコールなら移動処理をスキップさせる

    上記のような処理をするのはどのようにすれば良いのでしょうか?

    もしかしたらIFでは出来ないかもしれませんがヨロシクお願いします。

    念のため途中まで作成したコードを入力しておきます。

            // 必要な変数を宣言する
                string stPrompt = string.Empty;
                string path01 = System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
                string path02 = @"pdf\";
                string extensions = @"*.pdf";
                // 拡張子が .PDF のファイルを列挙する
                foreach (string FilePath in System.IO.Directory.GetFiles(path01, extensions))
                {
                    // フルパスからファイル名だけを取得
                    String File1 = System.IO.Path.GetFileName(FilePath);
    
                    //例外ファイル判定処理 予定地
    
                    //ファイル移動処理
                    System.IO.File.Move(path01 + File1, path01 + path02 + File1);
    
                    //例外ファイル判定処理 EXIT 予定地

    2013年4月9日 12:06

回答

  • foreachでは、continueを使ってループの次の処理に移動できます。

    foreach、in (C# リファレンス) - msdn

    ファイル名は普通の文字列なので、

    if(FilePath == "例外ファイル名")continue;

    のようにやればスキップできます。もちろん、

    if(FilePath != "例外ファイル名")
    {
     //移動処理
    }

    のように処理するもののときだけ移動処理を通るようにしてもかまいません。

    スキップするファイル名が複数ある場合、スキップするファイル名一覧を配列にしておき、ループごとにContainsメソッドを使って一覧にあるか確認し、あるようだったらcontinueするのが一番簡単だと思います。

    なお、フォルダ名とファイル名をつなげる場合は、System.IO.Path.Combineあたりを使うと間違いがありません。

    http://jeanne.wankuma.com/tips/csharp/path/combine.html


    • 編集済み tinq 2013年4月9日 14:07
    • 回答としてマーク Makoto Asao 2013年4月10日 7:05
    2013年4月9日 14:07
  • あまり動作確認できていませんが、以下の実装でいかがでしょうか。

    ご参考になれば幸いです。

    string destPath = System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\folder1\"; //移動先フォルダ
                var list = new List<string>() { "file1.pdf", "file2.pdf" }; //例外ファイル名リスト

                //例外ファイル名リストにないもののみforeach

                foreach (var file in System.IO.Directory.GetFiles(
                        System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "*.pdf").Where(u => !list.Contains(System.IO.Path.GetFileName(u)))) {
                    System.IO.File.Move(file, destPath + System.IO.Path.GetFileName(file));
                }

    • 回答としてマーク Makoto Asao 2013年4月10日 7:05
    2013年4月9日 22:52
  • 先に移動するファイルのリストを求め、後はそのリストに従って単純に移動する方法もあります。この場合、移動するファイルのリストが事前に手に入りますから、ユーザーにこれから移動するリストを表示し、移動するファイル数と共に、これで間違いないかを確認させることもできます。

    (参考)

    //移動対象ファイルのリスト
    var lines = new List<string>();
    lines.Add("hoge.pdf");
    lines.Add("fuga.pdf");
    lines.Add("moge.pdf");
    lines.Add("foo.pdf");
    lines.Add("bar.pdf");
    
    //例外として移動しないファイルのリスト
    var lines2 = new List<string>();
    lines2.Add("FUGA.pdf");
    lines2.Add("bar.pdf");
    
    lines.RemoveAll(s => lines2.Exists(p => p.ToUpper() == s.ToUpper()));
    
    foreach (string s in lines)
    {
    	System.Diagnostics.Debug.WriteLine(s);
    }

    ちなみに、デスクトップ上のファイル一覧をListにするには、例えば以下のように書けます。

    var files = Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "*.pdf").Select(p => Path.GetFileName(p)).ToList();


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/


    2013年4月10日 1:22
    モデレータ
  • Azulean様、AZUMAL

    凄く勉強になりました!!

    AZUMAL様のコードを適応させてみたところ、思い通りの動作をしてくれました!!

    正解は1つじゃないのでプログラムは奥が深いですねぇ~

    (使いかたはわかりましたが、どの部分がどの処理をしているか?はマダ理解出来るまで達していませんw)

    後続の初心者の方にアドバイス出来るくらいまでレベルアップしたいです!!

    また、つまずくと思いますがその時はヨロシクお願いします。^^;

    • 回答としてマーク Makoto Asao 2013年4月10日 2:00
    2013年4月10日 2:00

すべての返信

  • foreachでは、continueを使ってループの次の処理に移動できます。

    foreach、in (C# リファレンス) - msdn

    ファイル名は普通の文字列なので、

    if(FilePath == "例外ファイル名")continue;

    のようにやればスキップできます。もちろん、

    if(FilePath != "例外ファイル名")
    {
     //移動処理
    }

    のように処理するもののときだけ移動処理を通るようにしてもかまいません。

    スキップするファイル名が複数ある場合、スキップするファイル名一覧を配列にしておき、ループごとにContainsメソッドを使って一覧にあるか確認し、あるようだったらcontinueするのが一番簡単だと思います。

    なお、フォルダ名とファイル名をつなげる場合は、System.IO.Path.Combineあたりを使うと間違いがありません。

    http://jeanne.wankuma.com/tips/csharp/path/combine.html


    • 編集済み tinq 2013年4月9日 14:07
    • 回答としてマーク Makoto Asao 2013年4月10日 7:05
    2013年4月9日 14:07
  • == とか単なる Equals(string) だと大文字小文字を区別します。
    ファイル名の比較の場合は期待通りに動かないかもしれないので、大文字小文字を区別しない比較方法を使いましょう。

    http://msdn.microsoft.com/ja-jp/library/c64xh8f9(v=vs.80).aspx
    http://msdn.microsoft.com/ja-jp/library/system.stringcomparison(v=vs.80).aspx

    // LINQ が使えるなら、IEnumerable<T>.Contains のオーバーロードで大文字小文字を比較しない StringComparer を渡すと楽かも。

    2013年4月9日 15:23
    モデレータ
  • tinq様

    返信有難うございます!!

    すごく勉強になりました!!

    私のソースを流用すると

    foreach (string FilePath in System.IO.Directory.GetFiles(path01, extensions)==”例外ファイル名”)continue;

    となるのでしょうか?

    ただ、複数ファイル名がある場合は

       foreach (string FilePath in System.IO.Directory.GetFiles(path01, extensions))
                {
                    // フルパスからファイル名だけを取得
                    String File1 = System.IO.Path.GetFileName(FilePath);
    
                    //例外ファイル判定処理 予定地
          if ( strData.Contains("例外ファイル名[配列]") )
         
         //例外ファイルが含まれるので何もしない
    
          else
                    //例外ファイルが含まれないので、ファイル移動処理開始
    
    //パス結合処理
    string stFilePath01 =System.IO.Path.Combine(path01, file1);
    string stFilePath02 =System.IO.Path.Combine(path01,hath02,file1);
    
    //ファイル移動処理
                    System.IO.File.Move(stFilePath01,stFilePath02);
    
        

    上記のような処理になるということでしょうか?

    2013年4月9日 15:29
  • あまり動作確認できていませんが、以下の実装でいかがでしょうか。

    ご参考になれば幸いです。

    string destPath = System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\folder1\"; //移動先フォルダ
                var list = new List<string>() { "file1.pdf", "file2.pdf" }; //例外ファイル名リスト

                //例外ファイル名リストにないもののみforeach

                foreach (var file in System.IO.Directory.GetFiles(
                        System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "*.pdf").Where(u => !list.Contains(System.IO.Path.GetFileName(u)))) {
                    System.IO.File.Move(file, destPath + System.IO.Path.GetFileName(file));
                }

    • 回答としてマーク Makoto Asao 2013年4月10日 7:05
    2013年4月9日 22:52
  • 先に移動するファイルのリストを求め、後はそのリストに従って単純に移動する方法もあります。この場合、移動するファイルのリストが事前に手に入りますから、ユーザーにこれから移動するリストを表示し、移動するファイル数と共に、これで間違いないかを確認させることもできます。

    (参考)

    //移動対象ファイルのリスト
    var lines = new List<string>();
    lines.Add("hoge.pdf");
    lines.Add("fuga.pdf");
    lines.Add("moge.pdf");
    lines.Add("foo.pdf");
    lines.Add("bar.pdf");
    
    //例外として移動しないファイルのリスト
    var lines2 = new List<string>();
    lines2.Add("FUGA.pdf");
    lines2.Add("bar.pdf");
    
    lines.RemoveAll(s => lines2.Exists(p => p.ToUpper() == s.ToUpper()));
    
    foreach (string s in lines)
    {
    	System.Diagnostics.Debug.WriteLine(s);
    }

    ちなみに、デスクトップ上のファイル一覧をListにするには、例えば以下のように書けます。

    var files = Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "*.pdf").Select(p => Path.GetFileName(p)).ToList();


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/


    2013年4月10日 1:22
    モデレータ
  • Azulean様、AZUMAL

    凄く勉強になりました!!

    AZUMAL様のコードを適応させてみたところ、思い通りの動作をしてくれました!!

    正解は1つじゃないのでプログラムは奥が深いですねぇ~

    (使いかたはわかりましたが、どの部分がどの処理をしているか?はマダ理解出来るまで達していませんw)

    後続の初心者の方にアドバイス出来るくらいまでレベルアップしたいです!!

    また、つまずくと思いますがその時はヨロシクお願いします。^^;

    • 回答としてマーク Makoto Asao 2013年4月10日 2:00
    2013年4月10日 2:00
  • Azuleanさんも書かれていますが、ListのContainsは大文字小文字を区別しますから、注意して下さい。
    そのため、私が上記で紹介したコードはExistsを使っています。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2013年4月10日 2:18
    モデレータ
  • すみません、やはり壁に当たってしまいました・・・・

    拡張子を複数指定するという、シチュエーションも考えられるので安直にカンマで区切れは指定できるだろ・・・

    っと思っていたのですが無理でした^^;

    拡張子が複数有る場合はループさせるしか無いのでしょうか?

    2013年4月12日 1:26
  • 必要なのは移動対象のファイルのリストと、移動除外のファイルのリストの2つです。
    極端な話、拡張子毎に上記の2つのリストを用意して実行すれば目的が達せられます。効率を考えなければ、移動除外のファイルリストは、各拡張子共通に一つあれば事足ります。後は、拡張子毎に移動対象のファイルのリストを作成し、拡張子毎に移動を実行すれば良いでしょう。この拡張子毎の実行は、与えられた拡張子をループしながら実行することになります。Makoto Asaoさんが何を指して「ループさせるしか無いのでしょうか?」と言われているのかはっきりしませんが、この処理の部分に関してはループになります。

    さて、考え方を変えて、複数の拡張子のファイルを含まれる移動対象リストと、移動除外リストを1つずつ最初に用意してしまうという方法も取れます。こちらの方が考え方がシンプルでコードもわかりやすくなると思います。(ちなみに全ての移動対象リストを予め作成するので、移動を元に戻すUndoも簡潔に書くことができます。この機能が必要であるならばですが)
    問題は、複数の拡張子のファイルを含まれる移動対象リストをどう作るかですが、いろいろな方法が考えられますが、例えば以下のコードをご紹介しておきます。

    var extensions = new string[] { "*.pdf", "*.doc" };
    
    DirectoryInfo di = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.Desktop));
    
    List<FileInfo> files = extensions
                            .SelectMany(i => di.GetFiles(i, SearchOption.AllDirectories))
                            .ToList();
    
    System.Diagnostics.Debug.WriteLine("移動対象ファイルは以下の{0}個です。", files.Count);
    
    foreach (FileInfo s in files)
    {
        System.Diagnostics.Debug.WriteLine(s.Name);
    }
    
    //例外として移動しないファイルのリスト
    var lines2 = new List<string>();
    lines2.Add("AA.pdf");
    lines2.Add("ccc.doc");
    
    files.RemoveAll(s => lines2.Exists(p => p.ToUpper() == s.Name.ToUpper()));
    
    System.Diagnostics.Debug.WriteLine("実際に移動するファイルは以下の{0}個です。", files.Count);
    
    foreach (FileInfo s in files)
    {
        System.Diagnostics.Debug.WriteLine(s.Name);
    }


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/


    2013年4月12日 3:01
    モデレータ