none
ファイルアクセスのテクニックについて RRS feed

  • 質問

  • Win32APIのCreateFile(),ReadFile(),WriteFile()を使ったファイルアクセスについての質問です。

    開発環境やWindowsのバージョンには、あまり依存しないと思いますが、当方のメインツールがVC++なのと、色々なテクニックをご存じの方が多いと思い、こちらに投稿させて頂きました。

     

    Windowsは、FILE_SHARE_READでオープンして書き込み中のファイルに対して、別プロセス等からそのファイルの読み出しを行うと、読み出されたデータの内容は保証されない(関数は成功しても、データは正しく読み出せていない場合がある)。

     

    との事ですが、みなさんはこの様なファイルアクセスの場合でも正しく読み出し出来る様、どの様なテクニックで回避をされているのでしょうか?是非、ご伝授下さい。

     

    以上、よろしくお願いします。
    2007年9月18日 5:04

すべての返信

  • 書いたら、クローズする。

    2007年9月18日 7:01
  • レスありがとうございます。

    ですが、ファイルを書き出してる側のアプリはブラックボックスなので、読み出し側からは簡単にクローズ出来ないですし、そもそも書き込み中なのかも、簡単には分かりません。困ったものです…

     

    2007年9月18日 9:22
  •  ちょこころねにゃ さんからの引用
    レスありがとうございます。

    ですが、ファイルを書き出してる側のアプリはブラックボックスなので、読み出し側からは簡単にクローズ出来ないですし、そもそも書き込み中なのかも、簡単には分かりません。困ったものです…

     

    ファイルを書き出してる側のアプリがブラックボックスなら基本的には打つ手なしですね.

     

    書き込み側・呼び出し側,両方を自分で作れるなら,ファイルをメモリマップして,メモリアクセス経由で読み書きすることにすれば内容の同期は保証される(ある種の共有メモリとみなせる)のですが.

    あとはスレッド間で同じメモリにアクセスするように,Interlocked APIを使ったり排他制御を使ったりします.

     

    つまるところ,「ファイルを書き出してる側のアプリ」がそういう用途を想定し,かつトランザクションに関するプロトコルを事前に決めていないと無理な話です.見ず知らずのアプリに対して,そういうことができるとは思わない方が良いでしょう.

    2007年9月18日 9:26
  • ちょこころねにゃさん、こんにちは。

    そのあたりはファイルアクセスのテクニックというよりは、「排他処理のテクニック」 ではないでしょうか?

    排他処理はデータベースではアスペクト化されていますが、同等のことをコード上で実装すれば良いわけですよね。

    2007年9月18日 9:26
  • CopyFile()でコピーできる所にコピーして読むのはだめでしょうか。

    ただし、その変更中の場合に一体何が(どのバージョンが)読み込めれるかわかりません。壊れているかもしれません。

    2007年9月18日 10:16
  • みなさまレスありがとうございます。

     

     NyaRuRu さんからの引用
     ファイルをメモリマップして,メモリアクセス経由で読み書きすることにすれば内容の同期は保証される

    これは、ファイルがネットワーク越しにあり、今回の様なシチュエーションの場合に、すごく悲惨な事になります。(実験済み)

     

     NyaRuRu さんからの引用
     「ファイルを書き出してる側のアプリ」がそういう用途を想定し…中略…無理な話です

    まったくもってその通りなのですが、別レスに書きましたが、読み込もうとしたファイルが書き出し中なのかは簡単には分からないので、乱暴な言い方ですが、読み出そうとした全てのファイルで「正しくないデータを読み出す可能性を孕んでいる」と言えます。

    そのファイルのコンテナ的に破綻していればエラーの検出は可能でしょうが、そうで無ければ「文字化け」に近い状態なのでエラー検出は難しくなります。

     

     じゃんぬねっと さんからの引用
     ファイルアクセスのテクニックというよりは、「排他処理のテクニック」

    相手も協力してくれれば、排他処理の問題に落ち着くのでしょうが、相手が非協力的(笑)な場合は諦めるしか無いのでしょうか…

     

    具体例としては、ダラダラと計測ログを出力する他社のアプリのログビュアーを作っても、読み込んだデータの保証は無い訳です。

    また、別の例では、WMEでエンコード出力中のファイルは、ファイル的にもコンテナ的にもまだクローズしていません。しかし、WMP等で再生可能ですが、正しいデータが再生されている保証が無い訳です。

     

     IIJIMAS さんからの引用
    CopyFile()でコピーできる所にコピーして読むのはだめでしょうか。

    OSが「そーゆー使い方NO!」って言ってる訳ですから、ファイルをコピーしてもダメっぽいです。

    ひょっとしたら、カーネルモードに近い側でファイルアクセスすれば良いのかもしれませんが、そこまでみなさんやっていらっしゃるのでしょうか?

     

     

    2007年9月19日 2:29
  •  ちょこころねにゃ さんからの引用

     

     じゃんぬねっと さんからの引用
     ファイルアクセスのテクニックというよりは、「排他処理のテクニック」

    相手も協力してくれれば、排他処理の問題に落ち着くのでしょうが、相手が非協力的(笑)な場合は諦めるしか無いのでしょうか…

     

    具体例としては、ダラダラと計測ログを出力する他社のアプリのログビュアーを作っても、読み込んだデータの保証は無い訳です。

     

    うーん,諦めるしかないと書いたつもりなのですが,伝わってないでしょうか?

    仮にカーネルモードでフラッシュしたとしても,ユーザモードでバッファリングされている場合はどうしようもないですし.

    それとも,相手のプロセスはWeiteFileの前にバッファリングを行っていないことは分かっているのでしょうか?

    そうだとしても,書き込みが複数回に分けて行われ,途中に無効状態がある場合はやはり問題になりますし,データ更新のプロトコルを事前に定めておかないとやっぱり無理だと思います.

     

    自分で書き出し側・読み込み側の両方を作るのであれば,テクニック云々の話も出てくるでしょうが,書き出し側がブラックボックスなら,基本的に「諦めるしかない」で,テクニックでどうこうという問題ではないと思います.

     

    諦めたくないのであればもはや相手のプロセスに介入するぐらいしか手はないんじゃないでしょうか?

     

     ちょこころねにゃ さんからの引用

     IIJIMAS さんからの引用
    CopyFile()でコピーできる所にコピーして読むのはだめでしょうか。

    OSが「そーゆー使い方NO!」って言ってる訳ですから、ファイルをコピーしてもダメっぽいです。

    ひょっとしたら、カーネルモードに近い側でファイルアクセスすれば良いのかもしれませんが、そこまでみなさんやっていらっしゃるのでしょうか?

     

    みなさんそういうときは諦めて何もしてないんじゃないかと.

    それともOSの問題なんですか?

     

    唯一,他プロセスが開いているファイルを (状態が破綻してもいいから) とにかくバックアップしたいという場合は,Volume Shadow Copy をつかってスナップショットを取ったりすることはありますが.

    それにしても,今回のように破綻無く協調読み出しをしたいという目的は満たせません.

    2007年9月19日 2:42
  • レスありがとうございます。

     

     NyaRuRu さんからの引用
    うーん,諦めるしかないと書いたつもりなのですが,伝わってないでしょうか?

    失礼しました。諦めきれない性分なので…申し訳ない。

     

    みなさんは「全てのファイルアクセスに対して、読み込んだデータが正しくないかも知れないけど、まあしょうがない。」って事で納得されてる(and/or 諦めている)訳なんでしょうか?

     

    蛇足です…

     

     NyaRuRu さんからの引用
    書き込みが複数回に分けて行われ,途中に無効状態がある場合はやはり問題になりますし

     

    もし、誤解があると良くないので、具体的に書きますと、このシチュエーションでの「内容が保証されない」って言うのは、「単一ファイルに対して、プロセスAが4K分のデータの書き込みに成功して、プロセスBが4K分のデータの読み出しに成功しても、前者と後者の4Kのデータは等価である保証がない」と言う事です。(4Kじゃなくても、プロセスBが1Kしか読み出せなくても、プロセスAが書いた先頭1Kと読み出した1Kも等価では無い ってことですね)

     

    2007年9月19日 3:50
  • 外池と申します。

     

    ちょこころねにゃさんが想定されている操作と、皆さんが「上手く行かないこともある」と懸念されている操作と、前提としている想定の範囲が違っているのではないかと思います。(だから、ちょっと議論がすれ違っている)

     

    私は、少なくとも、シーケンシャルにデータをファイルを書き出すのみのプロセスを動かし、一方で、同一ファイルからシーケンシャルにデータを読み出すプロセスを立ち上げて動かすことをやっていますが、特に問題が起きたことはありません。特に読み出し側で、読み出し可能になっているファイルの末尾の位置をチェックして、読みこみの範囲をキチっと制御してやれば、問題が起きる可能性は、ちょと考えにくいです。(ちょこころねにゃさんの最後の文章を拝読すると、限りなくシーケンシャルっぽいのですが・・・、イケると思いますよ?)

     

    一方で、昔風の呼び方になりますが「ランダムアクセス」のように、ファイルのいろんな位置に書き込み動作が行われるような場合、おそらく読み出しもいろんな位置からデータを拾うようなことになるかと思いますが、読み出したデータが、常に最新(ファイルの書き込み要求を最新のものまで反映している)かどうか保証されないと思います。それどころか、読み出している側のアプリにとって、書き出し側のアプリがファイルの先頭の方をイジったり、中間あたりのどこかを更新したり、そのような「上書き」操作をしていることは知りようがないですよね? (ファイルを吐き出しているアプリがこのようなことをやっている可能性がある、かつ、ブラックボックスなら、私も打つ手ナシだと思いますが)

     

    用いている言語が違いますが、参考になれば・・・、

     

    私が用いている環境は、Visual Baisc .Netで、ファイルの書き込みには.Net FrameworkのStreamWriterでASCIIEncodingを用いています。AutoFlushはTrueにして、Writeするごとにバッファから吐き出すようにしています。読み取りにはStreamReaderを使っています。計測器から転送されたデータを一度ファイルに書き出し、一方で、データ処理するソフトがファイルから読み出してリアルタイムで処理していくようなシステムなのですが、一度も問題が起きたことはありません。

     

    2007年9月19日 4:48
  • レスありがとうございます。

     

     外池 さんからの引用
    シーケンシャルにデータをファイルを書き出す…中略…特に問題が起きたことはありません。

     

    これは「またまた上手く動作しているだけ」の様です。私感や実証結果では無く、MSKKSRの方の公式な見解です。

    ※ただし、.net Frameworkでの制限は分かりません。

    <愚痴>たまたまでも上手く動き続けてくれれば、問題はまだマシなのですがね…</愚痴>

    2007年9月19日 5:23
  • 基本的にOSが保障していない上、あきらめると言うのに私も一票入れます。

    書き出す側まで含めてシステム化する必要があるのにそれをやれない状況なのでは

    保障できるはずも有りませんし。(そもそも保障しろと言うほうに無理がある)

     

    読み出し側で任意のタイミングで読み出すようなオペレーションを可能にしておいて

    内容が化けてたら手動で読み直して見てねとか運用でカバーするしかないのではないかなぁ。

     

    2007年9月19日 5:57
  • 外池です。

     

    ここからは、気持ちの問題になってしまいますが・・・、ちょこころねにゃさんは、何を求めておられるのでしょうか?

     

    A)「こうすれば上手くいくらしい」という具体的な実装の方法論としての解決方法でしょうか?

     

    B)それとも、OS、コンパイラ、アプリなどの仕様を積み上げて、「これならば上手くいくことになっている」という、なんと言いますか、仕様上のロジックとしての解決方法でしょうか?

     

    現在のところ、データを吐き出すアプリ側の動作がブラックボックスである、とのことですので、私としては、A)の線で、実証的に仕事を進められるしか方法はないと思います。B)は、ここまでの議論で破綻してしまっていますので、無理なのではないかと。

     

    あと、暴論を言えば、「仕様」のハズが、実装のミスでそのように動いていないことも多々あるわけで、基本的にB)の考え方は「方針を立てる」時には良いのですが、最終的にはA)に頼らざるを得ないと思います。今の場合、「仕様」が「保証しません」というネガティブな情報なので、まぁ、どうしようもないわけですが。

     

    私ならばA)で仕事をしますね・・・。A)で解決する線で、興味深いというか、情報をいただけると皆さんもアイデアを出しやすいと思う点は・・・、

     

       データを吐き出すアプリは、毎秒、何バイトぐらいのデータをファイルに書き出すのでしょう?

       そのファイルは、どのようなエンコードのデータなのでしょうか? バイナリー? ASCII? 日本語交じりのShift_JIS?

       1行(1レコード)あたり何文字とか、何バイトとか、決まったフォーマットに整えられたファイルでしょうか?

     

    さらに言えばですね・・・、

     

    計測器が吐き出すログをリアルタイムに処理しても結果が「保証」はできないとしても、計測の進捗というか、上手く行っているかどうかの「目安」としては意味のあることではないかと思います。一通りの測定が終わって、ログのファイルがクローズされた後、確定のための処理を再度流せば、最終的な結果も「保証」できることになりませんか?

     

     

     

     

     

     

    2007年9月19日 6:05

  • レスありがとうございます。

     

     PATIO さんからの引用
    基本的にOSが保障していない上、あきらめると言うのに私も一票入れます。

     

    ご意見ありがとうございます。

     

     外池 さんからの引用
    何を求めておられるのでしょうか?

     

    冒頭の通り「みなさんはどうしてますか?」と出来るだけ大勢の方の意見をお聞きしたかっただけです。

    レス頂いた様に「諦める」と言うのも、もちろん貴重な意見ですし(みなさん、諦めてるんだ… と)、「私はこうやって回避してますよ」と言う様な情報を頂ければ、願ったり叶ったりな訳です。

     

     外池 さんからの引用
    ログのファイルがクローズされた後、確定のための処理を再度流せば、最終的な結果も「保証」できることになりませんか?

     

    それは、運用上で「途中経過の信頼性と、最終結果の信頼性が何処まで必要なのか?」話になってしまいますので…外池さまの事例を否定している訳ではありません。

    2007年9月19日 6:53
  • 外池です。

     

    「意見表明」でよければ、私の場合は「現場の測定屋」ですので、「諦めるな、やってみろ」に一票ですね。

     

    具体的には、先ほど書いたように、アプリがファイルを書き出す様子を調べて、上手く(行っていると思われる範囲で)読み出せるようにプログラムしてやって、あとはユーザーさんの判断に任せます。

     

     

     

    2007年9月19日 7:05
  •  外池 さんからの引用
    上手く(行っていると思われる範囲で)読み出せるようにプログラムしてやって、あとはユーザーさんの判断に任せます。

     

    レスありがとうございます。

     

     

     

    2007年9月19日 8:02
  • ファイルの状況が複雑さそうですが、

    Volume Shadow Copy API を使用してファイルコピーして定番オープン・クローズでは駄目なのでしょうか。

     

    私は使い方知りませんが・・・

    http://msdn2.microsoft.com/en-us/library/aa384645.aspx

     

    ご参考まで

     

    2007年9月19日 8:18
  • レスありがとうございます。

     

     marumusisan さんからの引用
    Volume Shadow Copy API を使用してファイルコピーして定番オープン・クローズでは駄目なのでしょうか。

     

    Shadow Copyは、ネットワーク上のリソースには使えなかった記憶があるので、包括的な方法では無いので難しいかもしれません。

    2007年9月19日 9:03
  • 意見だけで良いようですので・・・

     

    仕事のケースによりけりですね。

    ・安全性が必要なアプリならば、やらない(諦める)。

    ・その機能がどうしても必要ならば、ユーザー(上司)の了解の下で実装する。

    ・利用者が固定されたユーザーではない場合は、やらない(諦める)方向で話を進める。

    です。

     

    書き込みロジックが解っているなら、まだ救いようもあるのかも知れませんが、ブラック

    ボックスでは、基本的に諦める方向に行きますね。

    2007年9月19日 9:11
  • レスありがとうございます。

     

     FC-Shiro さんからの引用
    ・安全性が必要なアプリならば、やらない(諦める)。

     

    すみません、「やらない」と言う事はどういう事でしょうか?

    また、「諦める」と言うのは「安全性を犠牲にする」と言う事だと思うのですが…

    2007年9月19日 9:22
  • やらない=機能を実装しない。

    諦める =書き込み中と判断出来る場合は実行できないようにして機能は実装する。

         (プロセスの監視とか、そう言ったレベルでのチェック?)

    やる  =安全性を気にしないで実装する。

         (動いてそうに見えるから、これでいいや。)

     

    と認識してました。
    2007年9月19日 10:30
  • この質問、一つ重要な前提が抜けていませんか?

     

    ネットワーク越しのファイルアクセスのテクニックについて」

     

    が本題ではないですか?

    ちょこころねにゃさんはネットワーク越しの場合を想定しているのに対し、

    他の方々はローカルファイルを前提にしているため、「特に問題になってない」的な

    回答が多いのではないのでしょうか。

     

    #私はネットワーク越しに操作したことが無いので回答できません。

    2007年9月19日 11:25
  • レスありがとうございます。

     

    言葉尻を突っついている意図はありませんので、それだけは誤解しないでくださいね。

     

    ファイルを読み込む機能がある全てのアプリは、誰かが書き込み中のファイルを、書き込み中と気付かずに読んでしまう可能性が有る。その場合、データの内容の保証がない。

     

    と言う仕様が存在します。ここで一つ補足すると、「読み込めた位置までのデータは正常だけど、ファイルとしては破綻している」では無く、「ファイルとして破綻していなくても、読み込めたデータ自体に意味がない可能性がある」と言うことです。

     

    コンテナやデータ構造的にこれを検出出来れば、それに越したことはありませんが、それらでどうにもならない場合です。

     

    で、アプローチとして(あくまで、ニュアンスとして捉えてください)

     

    対策しない・諦める→表示や数値がおかしかったり、最悪アプリが暴走する可能性があるが、納得して貰い運用等で逃げる。

    対策する・とことんやる→どんな汚い手を使ってでも、正しいデータを読んでくる or 読み込みを防止・警告する。

    ...etc?

     

    と言う所に行き着くと思います。で、みなさんに、お伺いした次第です。

    2007年9月19日 12:01
  • レスありがとうございます。

     

     C.John さんからの引用

    この質問、一つ重要な前提が抜けていませんか?

     

    ネットワーク越しのファイルアクセスのテクニックについて」

     

    が本題ではないですか?

     

    いえ、そうではありません。

    ローカルだろうとネットワーク越しだろうが、冒頭の仕様は変わりません。

    「特に問題になってない」のは、繰り返しになってしまいますが「たまたま上手く動作している」だけです。

     

    ただ、「ローカルに対しては何らかの有効な手段があるが、ネットワーク越しだと別の方法でも打つ手無し」(又はその逆)だと、厳しいですね。と言うことです。

    2007年9月19日 12:12
  •  ちょこころねにゃ さんからの引用

    対策しない・諦める→表示や数値がおかしかったり、最悪アプリが暴走する可能性があるが、納得して貰い運用等で逃げる。

    対策する・とことんやる→どんな汚い手を使ってでも、正しいデータを読んでくる or 読み込みを防止・警告する。

    ...etc?

     

    と言う所に行き着くと思います。で、みなさんに、お伺いした次第です。

     

    ああ,やっと質問の意図が分かりました.

     

     ちょこころねにゃ さんからの引用
    レスありがとうございます。

    ですが、ファイルを書き出してる側のアプリはブラックボックスなので、読み出し側からは簡単にクローズ出来ないですし、そもそも書き込み中なのかも、簡単には分かりません。困ったものです…

     

    私はこの書き込みを読んで,「(一般論ではなく)特定のブラックボックスな書き出しアプリケーションがあって,そのアプリケーションが書き出すファイルを並行的に読み出したいのだが,そこで困っていて何とかしたい」という質問だと思ってました.

    なのでそのケースについてずっと書いていたのですが……

     

    そうではなくて,ちょこころねにゃさんの質問は,最初からずっと CreateFile(),ReadFile(),WriteFile() に関する一般論の話だったのですね……

     

    『インサイド Microsoft Windows 第4版 下』の以下の章あたりが今回の事例に関係してそうですね.

    • 11.1.3 キャッシュの整合性
    • 12.2.2 リモート FSD
    • 12.4.2 NTFSの高度な機能 -> 変更ロギング

    ローカルファイルへのアクセスであれば,外池さんの書かれているようなケースでも,「11.1.3 キャッシュの整合性」に書かれているような理由によって基本的には問題は起きないかと思います.まあこの辺りは CreateFile/ReadFile/WriteFile のドキュメントを信用するか,それとも OS の実装を信頼するかの話になりますが.

     

    また,ローカルのNTFSであれば,ある時点以降,ファイルの内容が更新されたかどうか監視できるので,ReadFile での読み出しが WriteFile と交差した可能性があるかどうか判定するという手も使えるかもしれません.

     

    リモートのファイルアクセスの場合はファイル共有に使っているプロトコル/相手のファイルシステムにもよりますが,OpLock (便宜的ロック) を使うのが一般的かと思います.(ローカルの NTFS にも OpLock は使えますが)

    .NET Framework から OpLock を使用する方法については,Jeffrey Richter が MSDN Magazine に寄稿していますので,それが参考になるかと思います.

    2007年9月19日 20:35
  •  ちょこころねにゃ さんからの引用

    ファイルを読み込む機能がある全てのアプリは、誰かが書き込み中のファイルを、書き込み中と気付かずに読んでしまう可能性が有る。その場合、データの内容の保証がない。

     

    と言う仕様が存在します。ここで一つ補足すると、「読み込めた位置までのデータは正常だけど、ファイルとしては破綻している」では無く、「ファイルとして破綻していなくても、読み込めたデータ自体に意味がない可能性がある」と言うことです。

     

    コンテナやデータ構造的にこれを検出出来れば、それに越したことはありませんが、それらでどうにもならない場合です。

     

    で、アプローチとして(あくまで、ニュアンスとして捉えてください)

     

    対策しない・諦める→表示や数値がおかしかったり、最悪アプリが暴走する可能性があるが、納得して貰い運用等で逃げる。

    対策する・とことんやる→どんな汚い手を使ってでも、正しいデータを読んでくる or 読み込みを防止・警告する。

    ...etc?

     

    と言う所に行き着くと思います。で、みなさんに、お伺いした次第です。

     

    前提として書き込み側に手を入れる事ができない、もしくは完全に外部のプログラムでブラックボックスである

    がないと話は変わって来ると思いますよ。

    私も以前に書いていますが、本来は書き込み側も含めた制御が必要でそこまで含めて書き込み中の読み込みを

    うまく避ける事ができるようなシステム化をすると言う前提ならあきらめる必要はないですし、そのからくりをひねり出す

    と言うのも有りでしょう。結局は何処まで表示されているデータを保障するかと言う話になりますけれども。

    で、前提条件が生きているなら私としてはOSが保障していない事を保障するなんて口が避けても言えませんから

    保障できませんという結論になります。その部分に対策するよりも運用でリカバリーできるような仕組みを考えた方が

    現実的と言う話です。参照側であれば、最悪落っこちても再起動すればデータを参照する事はできるでしょうから。

    結局、結果を保障できない以上はとことんやっても保障できない事には変わりないと言うのが私の意見です。

    2007年9月20日 6:10
  • NyaRuRuさん、PATIOさん レスありがとうございます。参考にさせて頂きます。

     

     

    2007年9月20日 6:50