質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

0回答

770閲覧

C# FileSystemWachter 1回おきに変更イベント発生

moto-a

総合スコア17

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

2クリップ

投稿2020/01/21 00:37

編集2020/01/24 12:13

お世話になります。

環境: C# (.netframework4.6.1) Windows10, 7

FileSystemWachterで、あるソフトから出力されるファイルの監視をしています。 (ソフトの仕様不明・ソース無)
ファイル変更イベントは発生しますが、ファイル変更イベント時に対象ファイルの読込を行うと次回のファイル変更イベントが発生しません。
ただし、次々回のファイル変更イベントは発生します。(必ず1回おきにファイル変更イベントが発生します)
対象ファイルの読込を行わないと正しく毎回ファイル変更イベントが発生します。
ファイル読込時のソースが外すと問題ありませんので影響していることは間違いないです。

ファイル読込時のソースをどのようにしたらよいでしょうか?

fileWatcher = new System.IO.FileSystemWatcher(); fileWatcher.Path = "c:\hoge"; fileWatcher.InternalBufferSize = 4096; fileWatcher.IncludeSubdirectories = false; fileWatcher.NotifyFilter = System.IO.NotifyFilters.Size; fileWatcher.Filter = "*.csv"; fileWatcher.Changed += watcher_Changed; fileWatcher.Created += watcher_Created; fileWatcher.Renamed += watcher_Renamed; isFileWatch = false; fileWatcher.EnableRaisingEvents = true; private void watcher_Changed(System.Object source, System.IO.FileSystemEventArgs e) { //デバッグログ出力 if (!isFileWatch) { isFileWatch = true; //↓ここから using (FileStream fs = new FileStream(e.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { using (TextReader sr = new StreamReader(fs, Encoding.GetEncoding("UTF-8"))) { String buff = ""; while ((buff = sr.ReadLine()) != null) { } sr.Close(); } fs.Close(); } //↑ここまでがあるとダメです。 isFileWatch = false; } }

ログ出力ソフトのテストプログラム

private StreamWriter sw; public Form1() { InitializeComponent(); sw = new StreamWriter(File.Open(@"C:\hoge\aaa.csv", FileMode.OpenOrCreate, FileAccess.Write,FileShare.Read),Encoding.Default); } private void button1_Click(object sender, EventArgs e) { sw.WriteLine(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")); sw.Flush(); } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { sw.Close(); }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YAmaGNZ

2020/01/21 00:45

どの程度の間隔でファイルの更新が行われるのですか?
moto-a

2020/01/21 00:48

30秒~1分程度です。 ソフトの仕様は不明ですが、動作から判断しますと、 出力ファイルをオープンしたままで、日付が切り替わるとファイルが変わりますが、 その際にCloseされるようです。
退会済みユーザー

退会済みユーザー

2020/01/21 00:51

ソースは ``` と ``` で囲ってください。インデントされて見やすくなるので。インデントされてないコードは質問者さん自身も読む気がしないのでは?
moto-a

2020/01/21 00:54

ありがとうございます。インデントを追加しました。
Zuishin

2020/01/21 01:04

読んでる間に次の出力があったから飛ばされただけという気がします。
YAmaGNZ

2020/01/21 01:10

読み込みの開始、終了にログ出力して、確実に読み込み終了後に更新が行われているか確認してはどうでしょうか。 提示ソースで監視し、30秒ごとにファイルを更新するプログラムを作成して確認しましたが、イベントは正常に発生しています。
moto-a

2020/01/21 01:17

出力ファイルの内容を確認したのですが、次の読込までに出力がありませんでした。 FileStreamを変更イベントで毎回オープンするのではなく、予めオープンしておいて使い回す形にしたらファイル変更イベントが正しく動作しました。
hihijiji

2020/01/21 01:29

変更を検出したら、そのファイルのコピーを作ってそっちを読んだらって案を出そうとしましたが > 予めオープンしておいて使い回す形 でいけるならそれが良さそうですね。
moto-a

2020/01/21 11:42

>FileStreamを変更イベントで毎回オープンするのではなく、予めオープンし>ておいて使い回す形にしたらファイル変更イベントが正しく動作しました 申し訳ありません。 さらに検証を進めましたが、上記のやり方でもうまくいかないことがわかりました。
Zuishin

2020/01/21 11:53 編集

最初の if 文の直前でログをとってみてください。 記録するのは isFileWatch です。 これが true になることがあるなら、読み込み中に対象ファイルが変更されています。 なぜかこの可能性が検証の方法の記述もなく軽くスルーされましたが、私はこの可能性は否定できないと思います。 というより最も可能性が高いと思っています。 そうでなければどこかで例外が握りつぶされていそうな気がします。
moto-a

2020/01/21 12:42

ご回答ありがとうございます。 最初の if 文の直前でログを取りましたが、イベント発生していませんでした。 fileWatcher.Error += new ErrorEventHandler(watcher_Error); を入れてみましたが、エラーは発生していないようです。 try catch無のミニマムコードで確認してみましたが、エラーは起きていないように思います。
Zuishin

2020/01/21 12:48

「isFileWatch を設定しなければ意図通り動く」というのは正確ですか? ここが正しくないなら前提が崩れます。
moto-a

2020/01/21 12:58

誤解を招くソースコードに問題で、申し訳ありませんでした。 コードを修正しました。 using (FileStream fs ~のブロックがあると正しく動作しません。
Zuishin

2020/01/21 13:18 編集

そこがメイン処理なので、それを取ると正しくどころか何もしなくなると思いますが。 とりあえず FileShare.ReadWrite は write が不要なので FileShare.Read に変えてみてください。 そしてブレークポイントを設定してステップ実行し、実際にどのように動いているのか確認してください。 一回おきというのもどうやってそれを確かめたのかよくわかりません。 本当に一回おきなのかというところも確かめ、方法を含めて書いてください。
moto-a

2020/01/21 13:36

FileShare.Readとすると、別のプロセスから書き込みできなくなる認識です。処理中にログ出力ソフトから書き込みできなくなってしまうと困るため、FileShare.ReadWriteとしました。 ソース内の「//デバッグログ出力」と記載した箇所でデバッグログを出力していますが、 ログ出力ソフト側でファイル出力があったタイミングが1回おきにデバッグログが出力されていました。 ここまで記載してみて、ログ出力ソフトが本当に正しく出力されているか確認していないことに気づきました。ログ出力ソフト側も合わせて調査してみます。
moto-a

2020/01/21 13:48

node-jsの「chokidar」を使用したソースですと思った通りのタイミングでファイル変更検知できました。 同様のことを別のWindowsアプリ「Terais」で行うと自分が作成したソースと同じタイミングでしか(1回おき)イベント発生しませんでした。 イベント発生しない場合に備えて、タイマーでファイルを定期監視することで補完する予定です。
Zuishin

2020/01/21 14:46

当然です。書き込みオープンできてはいけません。オープンのタイミングを調べるために外します。
Zuishin

2020/01/21 14:47

オープンは一日一回だけのはずです。
moto-a

2020/01/21 15:24

ありがとうございます。理解しました。 ご指摘通り、既にログ出力ソフト側はオープン済みのため、このソース以外で書き込みオープンするものはないはずですね。 明日、所要により試せないため、明後日に検証後に報告させていただきます。
moto-a

2020/01/24 12:15

結果はうまくいきませんでした。 ログ出力ソフトをエミュレートした仮想ログ出力ソフトを作成してみました。 こちらでテストするとそもそもFileSystemWatcherで変更イベントが起きませんでした。コード中のFlush()とした時点で変更がOS側に通知されるのかなと思いましたが…
dodox86

2020/01/24 12:59

StreamWriter.Flush()は恐らくキャッシュ上の書き込みデータをディスクに書き込むだけな為、FileSystemWatcherで監視すべき(あるいは対象の) イベントが発生しないのでしょう。SysinternalsのProcessMonitorで当該ファイルのアクセス状況を確認してみると、なにか分かるかもしれません。https://docs.microsoft.com/ja-jp/sysinternals/downloads/procmon
moto-a

2020/01/24 13:17

ご回答ありがとうございます。 Flush()時点ではプロパティのファイルサイズは変更になっていましが、更新日時などは変更されていませんでした。
dodox86

2020/01/24 13:26

フィルターが「System.IO.NotifyFilters.Size」でもサイズ変更を検知するのがファイルクローズ後だとすると、書き込み中のFlush()でイベントが発生しなくても仕方がないです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問