none
ファイル更新のタイミングを捕らえる方法について RRS feed

  • 質問

  • みなさま、こんばんわ!

    以下の問題について、良い解決方法が分かりません。
    アドバイスを宜しく願い致します。


    一定のインターバルでタイムスタンプをチェックする処理をバックグラウンドで動かし、
    ファイルが更新されたタイミングを捕らえようとしています。

    更新の有無を調べるには、FileInfoクラスの LastWriteTimeプロパティを使って、
    ファイルのタイムスタンプを読んでいます。

    しかし、不都合が出てきました。

    と言いますのも、上記方法でタイムスタンプを読めるのですが、まず更新のためファイル
    がオープンされた際に、一旦その時刻にタイムスタンプが更新され、その後、変更せずに
    クローズすると元のタイムスタンプに復帰しているようです。

    私の考え方では、更新のためにファイルをオープンしたタイミングを捕らえてしまい、
    更新されたタイミングを正確に捕らえていない事になります。

    目的のファイルが実際に更新された場合のみ捕らえたいのですが、これを実現するには
    どのような方法が有るのでしょうか。
    ここで得られるタイミングに同一内容を上書きされた場合も含んでも差し支え有りません。

    要するに、ファイルの書き込みが完了しクローズされた後のタイミングが必要です。

    何か良いヒントがあれば教えて頂きたく、どうぞよろしくお願い致します。

    2011年3月28日 16:02

回答

  • どの方法を使おうと、変更扱いになると思います。
    (FileSystemWatcher も同様のはず)

    今の挙動をお聞きする限り、Excel の動作に近いと思われます。
    Excel であれば、ファイルを開いた時に使用者(ファイルを開いている人)の情報を書き込み、ファイルを閉じたときにワークシートなどを変更していない場合は、使用者情報を戻すなり、更新日時を戻すなりの処理をして、何もなかったことにしているのでしょう。
    つまり、ファイルを開いた時点で何らかのバイト列の変更は行われるわけです。
    一時的な情報か、永続的な情報かは外部から一律の判断ができないので、”変更完了”は残念ながら定義できませんし、それを確実に検出する方法もありません。

    たとえば、ファイルが排他的にロックされている場合は更新とみなさないというロジックも考えられますが、共有ブックの場合は排他ロックされないが、開いただけで一時情報の変化が発生するのでこれをカバーできません。バイト列を比較する方法も、一時情報が書き込まれて変更があること、重くなることを考えると採用できません。こういった状況なので完璧な方法はないと言えます。
    どこまで実現するか決めて、仕様として割り切るしかない部分だと考えます。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年3月28日 22:34
    モデレータ
  • その状況下ですと、以下で大丈夫かもしれません。ファイルロックの確認方法も参考になると思います。

    監視により作成/変更が通知されたファイルを開くには?
    http://www.atmarkit.co.jp/fdotnet/dotnettips/284watchopen/watchopen.html

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年3月29日 1:53
    モデレータ
  • >FileクラスのReadAllLinesメソッド等をtry し、例外を catch する方法くらいしか思いつきません。

    バイナリのファイルでこのような読み方をするのはちょっと危険ですし、ロックされてない場合に無駄に読むことになります。

    単に書き込み用にファイルを開いて例外チェックとかがシンプルじゃないですかね?
    Excelのファイルの開き方が読み込み共有もされていない状態なら、読み込み用に開くのでもいいですが。

    2011年3月29日 1:56

すべての返信

  • FileSystemWatcherが使えませんか?

    FileSystemWatcher クラス (System.IO)

     


    Blog:プログラマーな日々 http://d.hatena.ne.jp/JHashimoto/
    • 編集済み jhashimoto 2011年3月28日 22:24 スペルミスを修正
    2011年3月28日 22:23
  • どの方法を使おうと、変更扱いになると思います。
    (FileSystemWatcher も同様のはず)

    今の挙動をお聞きする限り、Excel の動作に近いと思われます。
    Excel であれば、ファイルを開いた時に使用者(ファイルを開いている人)の情報を書き込み、ファイルを閉じたときにワークシートなどを変更していない場合は、使用者情報を戻すなり、更新日時を戻すなりの処理をして、何もなかったことにしているのでしょう。
    つまり、ファイルを開いた時点で何らかのバイト列の変更は行われるわけです。
    一時的な情報か、永続的な情報かは外部から一律の判断ができないので、”変更完了”は残念ながら定義できませんし、それを確実に検出する方法もありません。

    たとえば、ファイルが排他的にロックされている場合は更新とみなさないというロジックも考えられますが、共有ブックの場合は排他ロックされないが、開いただけで一時情報の変化が発生するのでこれをカバーできません。バイト列を比較する方法も、一時情報が書き込まれて変更があること、重くなることを考えると採用できません。こういった状況なので完璧な方法はないと言えます。
    どこまで実現するか決めて、仕様として割り切るしかない部分だと考えます。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年3月28日 22:34
    モデレータ
  • Azuleanさん、詳しく説明くださり、有難うございます。

    仰る通り、Excelファイルで確認しており、更新のタイミングを捕らえたい
    のも Excelファイルです。

    今、必要なのは、該当ファイルが更新された可能性があった場合に、その
    タイミングが捕らえられれば良いと思っています。
    即ち、データの内容が変化せずに上書きされた場合を含んでも、やむを得ず
    『可』としようと思っています。

    また、チェック対象の Excelのファイルは、共有ブックになっておらず、更に
    一度更新が行われた後、再び更新されるまでに一定の時間的な感覚が保証され
    ています。

    よって、教えて頂いた事柄を参考にして、

     1.タイムスタンプを確認する。
     2.続いて、ファイルのロック状態を確認する。

    上記のチェックを一定間隔で繰り返し、

     【タイムスタンプ変更あり】and【ファイルのロック無し】
     
    をもって、【更新が行われた】と判断しようかなと考えています。


    所で、これに関連してもう一点質問させてください。

    ファイルのロックを確認する方法ですが、

    FileクラスのReadAllLinesメソッド等をtry し、例外を catch する方法
    くらいしか思いつきません。

    このような目的で使用する最適な方法が有れば教えてください。

    どうぞ、よろしくお願い致します。

    2011年3月29日 1:32
  • その状況下ですと、以下で大丈夫かもしれません。ファイルロックの確認方法も参考になると思います。

    監視により作成/変更が通知されたファイルを開くには?
    http://www.atmarkit.co.jp/fdotnet/dotnettips/284watchopen/watchopen.html

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年3月29日 1:53
    モデレータ
  • >FileクラスのReadAllLinesメソッド等をtry し、例外を catch する方法くらいしか思いつきません。

    バイナリのファイルでこのような読み方をするのはちょっと危険ですし、ロックされてない場合に無駄に読むことになります。

    単に書き込み用にファイルを開いて例外チェックとかがシンプルじゃないですかね?
    Excelのファイルの開き方が読み込み共有もされていない状態なら、読み込み用に開くのでもいいですが。

    2011年3月29日 1:56
  • trapemiya さん、有難うございました。

    参考になる URL を教えて頂き、有難うございました。
    (何時もここを探すんですが、今回旨く見つけられませんでした)

    いま、流し読みしてきたんですが、この後、詳しく読んでみます。

    2011年3月29日 2:38
  • なちゃ さん、有難うございます。

    ご指摘の通りですネ。

    他所でオープンしていない時に、無駄な読み込みが行われてしまいます。

    仰る通り、ちょっと書き込むフリをして、ロックしているかどうか確認
    することにします。

    貴重なアドバイス有難うございました。

    概ね方向性が見えてきましたので、このスレッドはこの辺りでクローズ
    させて頂きます。

    みなさま、色々と有難うございました。
    これからも、どうぞよろしくお願い致します。

    2011年3月29日 2:44
  •  どうやって実現するかはまったくわかりませんが。

     Sysinternals の ProcessMonitor で、ファイル システムを見ていると、Operation 列に「CreateFile」や「CloseFile」と出てきます。この、「CloseFile」だけをウォッチすれば良いのではないでしょうか。

     どうやって実現するかはまったくわかりませんが、こういうツールが(2006年以前は)マイクロソフト以外の会社が作れたと言うことは、公開されたドキュメントがある、ということだと思います。


     ん?ずっと「誰か拾い上げるコードつくってくんないかな」と他力本願モードだったのだが、「FileSystemWatcher の中に、この状態を指定するプロパティを作れ」という要望を上げればいいのか?


    Jitta@わんくま同盟
    2011年3月30日 14:05