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

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

ただいまの
回答率

89.65%

複数の端末から1つのファイルを操作するには

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,440
退会済みユーザー

退会済みユーザー

visual studio2017、C#で
複数の端末からファイルサーバー上の1つのファイルを読み書きするプログラムを作りたいと考えています。

以下、質問の修正依頼があり、自分でもわかりにくい質問だったと思うので殆ど内容が変わっています。

実現したいこと

  • 複数のPCから1つのファイル(情報)の読込み、変更
    ファイルの中身は1行で
    01,0,1,0
    02,0,0,1
    .
    .
    .
    19,0,1,0
    のようなCSV形式になっており、[モノの番号,状態1,状態2,状態3]という具合です。
    モノは1から19まであります。ファイルは19個あります。状態は1か0で表し、1の場合はオン、0の場合はオフです。
    モノに対し3つのステータスがあり、それぞれのステータスのオン、オフがあります。

このファイルの情報をもとに画面上の[モノ]の見た目を変化させています。
たとえば、ファイル01の中身が[01,1,0,0]だった場合、画面上のモノ01のステータス1がオン、2がオフ、3がオフといった具合です。

この19個ファイルに対しての書込み、読込みを複数のPCから行いたいです。
書込みは状態1、2、3、の[0か1か]を書き換えるだけ。
読込みはファイルが書き換えられた時点で読込み、その情報をもとに画面上のモノの状態を変化させます。
前提として、ファイルが書き換えられた時点でファイルを読み込む必要があるので、FileSystemWatcherを使って19個のファイルを監視しています。

問題になっていること

問題1
ファイルの書き換えをした時点でFileSystemWatcherが働く。

FileSystemWatcherのイベントでファイルを読み込みに行くが、別のプロセスが使用中とエラーが発生する。
(おそらくですが、ファイルの書き換えがまだ終了していない。)

//sensor.csvファイルを指定された値に変更するメソッド
        public void SensorSettingChange(string path,int to,string value) {
            string filePath = ConfigurationManager.AppSettings["SensorPath"] + path;
            string[] snInfo;
            //csvファイル読込
            try {
                using (FileStream fsr = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                using (StreamReader sr = new StreamReader(fsr)) {
                    snInfo = sr.ReadLine().Split(',');
                }
                snInfo[to] = value;
                //変更した値をcsvファイルに書込
                using (FileStream fsw = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write))
                using (StreamWriter sw = new StreamWriter(fsw)) {
                    sw.WriteLine(string.Join(",", snInfo));
                }
            } catch {
                //エラー通知
            }
        }

ファイル書き換えのメソッドです。
まず、書き換える前の状態を知るために一度書き換えるファイルを読み込み、配列に入れます。
そして引数をもとに、配列の中身を変更し、書き換えを行っています。

usingでストリームを閉じているはずなのですが、読込み時にエラーが発生する場合があります。
しかし、エラーが発生しない場合もあります。

問題2
ファイルの書き換えを複数のPCから同時に行う

別のプロセスが使用中とエラーが発生する。

こちらは先ほどの書き込みメソッドのCatch部分に”他の端末から操作している可能性があります。”とメッセージを表示しているのですが、できれば他の端末の処理が終わるまで自動で待ち、ファイルのアクセスが可能になった時点で操作を反映させたいと思っています。(ユーザーからそうして欲しいと依頼があったため)

自分でやってみた解決策

問題1に対して。。。
おそらく、FileSystemWatcherが反応した時点で書き込みのストリームが閉じられていないので、イベントが発生した時点でスレッドを50ミリ秒止めています。
こうすることでエラーは発生しなくなりました。
しかし、本当に書き込みのストリームが閉じられていないのが原因か分からない状況です。

問題2に対して。。。
書込みメソッドのcatchの部分でもう一度書き込みメソッドを呼び出し、成功するまで永久ループをさせています。
しかし、これではかなり危険だと思っていて何か他の方法がないかと探しています。

ここでデータベースを用いることで排他制御ができるのではないかと思い、修正前の質問に至ります。
データベース排他制御を使うことで問題2が解決できるのではないかと考えていますが、ファイルの情報量がかなり少ないですし、採用するほどのものなのかがわかりません。
また、データベースにしてしまうと、ファイル監視ができなくなるのではないかと思い悩んでいます。

この2つの問題を解決するにはどのような作りをすると良いと思いますか?
皆様のご意見を参考にいろいろ試したいと思っています。よろしくお願いします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    退会済みユーザー

    2018/11/28 17:50

    同一ファイルの同一状態を変更する。ということは十分にあり得ます。また、ファイル監視ができなくなると、ファイルが変更された時点でファイルの情報を読み込むイベントがなくなってしまうからです。

    キャンセル

  • kenshirou

    2018/11/29 11:54 編集

    ファイル監視をしたい理由は、ファイル更新があった場合にその内容を各ユーザ側のアプリにも読み込ませる、ということでしょうか?あと、ユーザがファイルのデータを修正しようとする際、現在の情報はユーザは知り得るのでしょうか?(例えば、モノ1の状態2が現在OFFなのでONにしよう、ということなのか、それとも、モノ1の状態2の状況は分からないが、OFFだったらONに変更しよう、ということなのか)

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2018/11/30 13:55

    ファイル監視の理由はその通りです。ユーザーがファイルを変更するときは、モノの状態を知った上で変更をかけることを前提としています。

    キャンセル

回答 2

+3

まずは本来なにをしたいがためにそのようなことをしてるか、というのを提示しましょう

ファイルを作りたい?ならデータベース持ち出してる場合じゃないだろうし、データベースに登録してなにをするんだ?という話になるし。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/28 15:26

    確かに、本来どういうことをしたいのか、とういう一番大事な部分が読み取れませんね。。
    すみませんでした。もう一度よく考え、質問を修正します。
    ありがとうございました。

    キャンセル

checkベストアンサー

+1

問題1についてですが、そもそも、以下のコードのcsvファイル書込時のFileStreamコンストラクタの第4引数は正しいのでしょうか?

   //変更した値をcsvファイルに書込
   using (FileStream fsw = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write))


FileShare.Writeだと、このファイルへの他からの書き込みは許可するが、読取は許可しないことになりますので、FileShare.Readにして読取を許可した方が良いのではないでしょうか?
これであれば、FileSystemWatcherのイベントが発生した時点では、読取は許可されているので、例外の発生なく、読取モードで変更後の内容を得られるかも知れません。

また、問題2については、私ならタイマーを使用してリトライさせます。
例外発生したら、タイマーをセットして、タイマーTickでリトライ。
安全のため、何回かリトライしてもダメだったらメッセージを出して中断する、という感じです。
タイマーのインターバルが1秒くらいがいいのか、0.5秒くらいがいいのか、は実用的な程度にすればよいと思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/30 15:56

    確かに、FileStreamの第4引数が間違っていました。Readにすることによってエラーがなくなりました。
    問題2の複数からの書き込みですが、権限機能つけました。権限のフラグ管理も結局はファイルなのですが、ファイル内容が単純で、万が一競合が起き、ファイルが消えてしまってもユーザーの方で復旧できるので大丈夫。という内容でOKをいただきました。
    ここまで詳しく掘り下げ、ご回答していただき本当にありがとうございました。

    キャンセル

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

  • ただいまの回答率 89.65%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる