C++ :非排他モードでファイルを開く
-
09-06-2019 - |
質問
ログ ファイルを解析し、特定のデータをサーバーに送信するアプリケーションを開発する必要があります。Linux と Windows の両方で実行する必要があります。
この問題は、ログ ローリング システム (名前に .1 を追加すると、同じ名前の新しいシステムが作成されます) をテストするときに発生します。Windows では (Linux ではまだテストしていません)、「入力モード」(ios::in) で開いた場合でも、std::ifstream() (排他アクセス?) で開いたファイルの名前を変更できません。 。
非排他的な方法でファイルを開くクロスプラットフォームの方法はありますか?
解決
非排他的な方法でファイルを開く方法はありますか?
はい、Win32 を使用して、さまざまな FILE_SHARE_Xxxx フラグを CreateFile に渡します。
クロスプラットフォームですか?
いいえ、プラットフォーム固有のコードが必要です。
厄介な下位互換性の問題のため (DOS アプリケーションはシングルタスクなので、その下からファイルを削除できるものは何もないと想定しています。つまり、fclose() と fopen() を何も問題なく実行できること。Win16 は DOS アプリケーションの移植を容易にするためにこの前提を保持し、Win32 は Win16 アプリケーションの移植を容易にするためにこの前提を保持しましたが、これはひどいことです)、Windows のデフォルトではファイルを排他的に開きます。
基盤となる OS インフラストラクチャは、オープン ファイルの削除/名前変更をサポートしています (ただし、メモリ マップされたファイルは削除できないという制限があると思いますが、これは *nix に見られる制限ではないと思います) が、デフォルトのオープン セマンティクスではサポートされていません。
C++ にはこのような概念はありません。C++ オペレーティング環境は DOS オペレーティング環境とほぼ同じです。他のアプリケーションは同時に実行されないため、ファイル共有を制御する必要はありません。
他のヒント
排他モードを必要とするのは読み取り操作ではなく、名前の変更です。これは、ファイルを新しい場所に移動することと本質的に同じであるためです。
よくわかりませんが、これは不可能だと思います。代わりにファイルをコピーし、後で読み取られなくなった古いファイルを削除/置換してみてください。
Win32 ファイルシステムのセマンティクスでは、名前を変更するときにファイルが (どのモードでも) 開いていないことが必要です。ファイルを閉じて名前を変更し、新しいログ ファイルを作成する必要があります。
Unix ファイルシステムのセマンティクスでは、ファイル名は i ノードへの単なるポインタであるため、開いているファイルの名前を変更できます。
ファイルから読み取るだけの場合は、Windows API CreateFileを使用して実行できることがわかります。file_share_delete |を指定するだけですfile_share_read | dwsharemodeへの入力としてのfile_share_write。
残念ながら、これはクロスプラットフォームではありません。しかし、Linux でも同様のことが起こるかもしれません。
CreateFile の詳細については、msdn を参照してください。.
編集:グレッグ・ヒューギルのコメントについて簡単にメモします。FILE_SHARE* のものを使ってテストしました (100% 確実です)。また、読み取り専用で開き、FILE_SHARE* パラメーターを指定すると、Windows でファイルの削除と名前変更の両方を行うことができます。
ファイルを開いたままにしないようにしてください。これにより、たとえばアプリがクラッシュした場合に奇妙な事態が発生します。私ならどうするか:
- (読み取り/書き込み/新しいファイルへのロールオーバー) を 1 つのクラスに抽象化し、そのクラス内の新しいファイルにロールオーバーしたいときにファイルを閉じるように手配します。(これが最も適切な方法であり、ロールオーバー コードがすでにあるので、すでに半分まで到達したことになります。)
- 複数の読み取り/書き込みアクセス ポイントが必要で、fstream のすべての機能が必要で、完全なラッパーを書きたくない場合、私が考える唯一のクロスプラットフォーム ソリューションは、ファイルが必要ないときは常にファイルを閉じることです。 、ロールオーバーする必要がある場合は、ロールオーバー コードでファイルへの排他的アクセスを数回試行してから、あきらめます。