#pragma twice

KAB-studio > プログラミング > #pragma twice > 270 Version 14.03 ファイルの排他処理

#pragma twice 270 Version 14.03 ファイルの排他処理

前のページへ 表紙・目次へ 次のページへ

 Version 14.03
ファイルの排他処理

今回は、ファイルにロックを掛けて他のアプリが開けないようにする方法
について説明します
それをすれば……はいた、だっけ
そう、排他処理をすることができるので、あるプロセスが開いている間は
他のファイルが開けないようにすることができます
はー、便利ねー
さて、ファイルロックの方法について説明します。まず、ファイルロック
は〈ファイルを開くとき〉に行います
ファイルを開く?
そう。ファイルを開くときにロックを掛けると、そのファイルを閉じるま
ではロックがかかったままになります
なるほど、開くときにロックを掛けて、閉じるときにロックを解除する、
と。ん? でもさ、 fopen() にそんな機能あったっけ?
ないよ。 fopen() はランタイムだから、どんな OS でも使えるように
なっているけど、ファイルロックの機能は OS 個別の機能だからね
そういう機能はランタイムに入れられない、と。あ、もしかして API 使
うの?
そういうこと。 Version 5.15 ( No.080 ) の CreateFile() を使いま

確か、ランタイムも結局これ使ってるんだよね
 OS 個別の機能を隠して、汎用的に使えるようにしたのがランタイムだか
らね
でも、この API 結構使うの面倒だったような……
大丈夫、今回はファイルロックの部分しか見ないから
んー
じゃ、実際の例を見てみます

HANDLE g_hFileFrom = NULL;

void OpenFile( CString p_cStr )
{
    // ファイルを開きます。
    g_hFileFrom = CreateFile
        ( p_cStr
        , GENERIC_READ
        , 0             // A
        , 0
        , OPEN_EXISTING
        , 0
        , 0 
        );

    // 確認用。 FFFFFFFF だと開くのに失敗しています。
    TRACE( "%X\n", g_hFileFrom );
}

エラーチェックとかすごく省いているから注意して
ってゆーか、 CloseHandle() しなくていーの?
本当はした方がいいけど、テストだから今回は省略
んー、使い方って、引数の p_cStr にファイルパス渡せばいいの?
そう。フルパスを渡すのが手っ取り早いかな。 Version 5.30 ( No.095 ) 
を参考にしてファイルダイアログを使うっていうのもありかも
それこそテストだったら必要なさそう……
ちなみに

void Use_OpenFile()
{
    OpenFile( "Test.txt" );
}

っていうふうにファイル名だけでも通ります。ただし、デバッグ実行する
ときにはワークスペースのフォルダ、つまり .dsw ファイルが置いてある
フォルダに置くようにしてください
 exe の置いてあるところっぽいのにね
デバッグ実行の時は、カレントディレクトリが変わるからね……それと、
このファイルは当然前もって作っておいてください
普通のテキストファイルでいいの?
それでOK。この関数の呼び出し方だけど、ダイアログアプリで、ボタン
を押したら呼ぶ、っていうのが簡単かも
いつものテストアプリみたいな感じね
念のため書いておくと Version 4.01 ( No.051 ) で紹介した方法です
これでOK?
それでOK
んじゃそれを指定してプログラム実行! ……で?
そのテキストファイルをメモ帳で開いてみて
ほい……あ!

プロセスはファイルにアクセスできません。別のプロセスが使用中です。

あらー、なんか簡単にロック掛かっちゃった
そう、実は CreateFile() で開くと、デフォルトでロックがかかるんで

ちょっと意外。デフォルトは開ける、って状態だと思ったのに
この辺は安全でいいかも。それと、この状態は〈本当に何もできない〉
ってことだから
どゆこと?
つまり、見るだけでもできないし、ファイルのコピーもできません
コピーもできないの? ……うわ、こんなダイアログ出た

Test をコピーできません。共有違反がありました。
送り側または受け側のファイルは使用中の可能性があります。

複製すら作れないんだ……
前回の例で言えば

キャンセル
1. Excel Aが開いている間は Excel Bは開けないようにする

に当たるかな
どうしようもできなくしちゃうわけねー
この状態なら完全な排他制御。これならアプリAが使っているときに
アプリBが読み込んで待ちがった処理をする、ってことがないでしょ
確かに……本当の排他制御、ってわけね
さて、今の状態は読み書き両方できない状態です。これを、読み込むのは
できるようにします
リードオンリーってことね
具体的には、 CreateFile() の第3引数にフラグをセットすればOK

    // ファイルを開きます。
    g_hFileFrom = CreateFile
        ( p_cStr
        , GENERIC_READ
        , FILE_SHARE_READ   // ここを変更。
        , 0
        , OPEN_EXISTING
        , 0
        , 0 
        );

 FILE_SHARE_READ ってのを渡せばいいのね
これで実行して、ファイルをメモ帳で開いてみて
お、今度は開けた!
それを上書き保存してみて
ほい……あ

ファイル Test.txt を作成できません。
パスおよびファイル名が正しいか確認してください。

アプリによっては最初に開くときに【上書き禁止】って出るものもありま

なるほど、さっきと違って読み込みはできるけど、書き込みはできないっ
てわけね
前回の例で言うなら

読み取り専用
2. Excel Aが開いている間は Excel Bは書き込めないようにする

に当たるかな
読み取り専用ねー
排他制御とか考えない場合には、これが一番普通かも。フラグなしの状態
だと複製コピーすらできないから問題だし
問題?
バックアップコピーとかできなくなるから
うわぁ……
読み取り専用で、あとは〈最新の状態を取得する〉っていう機能を入れれ
ば同期処理としては十分だから、この読み取り専用が一番いいかも
その〈最新の情報を取得〉とかが難しそうだけど……
最後は、全部許可

    // ファイルを開きます。
    g_hFileFrom = CreateFile
        ( p_cStr
        , GENERIC_READ
        , FILE_SHARE_READ | FILE_SHARE_WRITE    // ここを変更。
        , 0
        , OPEN_EXISTING
        , 0
        , 0 
        );

実行! うわー、保存もできちゃう
 FILE_SHARE_READ と FILE_SHARE_WRITE 、両方のフラグを立てるとなん
でもできるようになります
こりゃまずいね……
でも fopen() はこれだから
へ?
 fopen() で開いたファイルは、他のアプリから読み書きし放題、ってこ

それまずそう……ってことは foepn() って使えないじゃん!!
そうなんだよね、ある程度ちゃんとしたアプリを作る場合には fopen() 
は使わない方がいいかも
かといって API 使ってファイル操作って面倒よね……
さて、ここまでファイルの排他処理について説明してきましたが、実はこ
れはある意味〈雑〉なやり方です
え、そうなの?
こういう形でファイルのロックを掛けた場合、ファイルが使えるように
なっても教えてくれないから
見張る必要がある?
そういうこと。ファイルの排他処理のメリットとデメリットをあげると

■メリット
・お手軽
・他のアプリからファイルを守る

■デメリット
・同じアプリでもプロセスが違うとアクセスできない
・通知が面倒

細かい処理には向かないってことね
というわけで次回へ続く!

/*
    Preview Next Story!
*/
ファイルロックって、確かにおおざっぱな感じよね
というわけで次回は同期オブジェクト
……なーんか〈同期〉って言葉、慣れないかも
というわけで次回
< Version 14.04 同期オブジェクト >
につづく!
上に〈シンクロ〉ってふりがな振ってあると思えばいいかな
シンクロって、水泳のがインパクト強いし……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。