2013-05-14 5 views
14

プロセスがログファイルを読み込もうとしているのに、NLogによって現在開いているファイル共有の問題があります。問題を診断する際に、私は驚くべきことを見つけました。次は失敗します。ファイル共有が期待通りに機能しない

using (var fileStream1 = new FileStream("test.file", FileMode.Append, FileAccess.Write, FileShare.Read)) 
using (var fileStream2 = new FileStream("test.file", FileMode.Open, FileAccess.Read, FileShare.Read)) 
{ 
} 

を二FileStreamコンストラクタ呼び出しがで失敗します。

System.IO.IOException was unhandled 
    Message=The process cannot access the file 'c:\...\test.file' because it is being used by another process. 
    Source=mscorlib 
    StackTrace: 
     at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 
     at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath) 
     at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) 

これは最初のFileStreamは読書を共有する意思を示したという事実にもかかわらずです。

using (var fileStream1 = new FileStream("test.file", FileMode.Append, FileAccess.Write, FileShare.Read)) 
using (var fileStream2 = new FileStream("test.file", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
{ 
} 

あの、はい、第二の流れは、実際に問題を迂回開くときよりアクセスを要求している:私はさらに驚くべき発見は、これが機能するということでした。私はそれがなぜそうであるかについて完全に困惑し、私が何かを誤解していると仮定することしかできません。私はAPIのドキュメントを読んだことがありますが、それは動作する方法とは逆に、これがどのように動作すべきかについての私の現在のメンタルモデルをサポートしています。ここで

docsからいくつかのサポート引用符です:

この列挙の典型的な使用は、2つのプロセス が同時に同じファイルから読み込むことができるかどうかを定義することです。たとえば、ファイルが で開かれていて、Readが指定されている場合、他のユーザーは のファイルを開くことができますが、書き込みはできません。

は、ここに別の宝石です:

次のFileStreamコンストラクタは、既存のファイルや助成金、他のユーザ(リード)へ は、読み取り専用アクセスを開きます。

FileStream s2 = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.Read);

誰もが、この動作上の任意の光を当てることができます。 .NET 4%Windows XPでこれをテストしています。

答えて

15
var fileStream2 = new FileStream(..., FileShare.Read) 

これは多くのプログラマを引き上げます。誰もがこのの共有を追加したと仮定します。そうではありませんでした。元のファイルへのアクセス要求は既に許可されており、再度指定すると何も変わりません。代わりに書き込み共有を拒否します。誰かが既に書き込みアクセス権を持っているので、それはうまくいかない。そして、それを使用している、あなたはその権利を削除することはできません。したがって、ファイルへのアクセス要求は失敗します。

は、にFileShare.Writeを含める必要があります。

+1

ありがとうございます。だから、この誤解は非常に流行していても、ドキュメントは間違っている/間違っている? –

+0

2番目のストリームに 'FileShare.Write'を含めることを意味します。 – rookie1024

0

第四パラメータあなたは

シェア
ファイルはプロセスによって共有される方法を決定する定数を渡します。

は、他のユーザーがファイルを開くモードを決定します。つまり、明らかに、ファイル共有モードでファイルを開こうとしているときに、書き込みモードで同じファイルを開いていると、操作が失敗します。

+0

3位ではなく、4位です。そして、 'FileShare.Read' _読み込みのためにファイルを開くことを許可します。 –

+0

申し訳ありません、修正:) – elevener

+0

FileShare.Read - "読み込みのためにファイルを開くことができます " - 書き込みはできません。あなたはすでにその共有モードで禁止されているものを書くためのファイルを開いています。関数は何をすべきですか? – elevener

1

実際には、fileStream2は、書き込み(または追加)のために開いているファイルへのその後のアクセスをfileStream1で変更できないということです。 は、ファイルへのアクセスが既にWriteのプロセスが存在しない場合にのみ、その後のアクセスのために「レガシー」として正常にファイルを開きます。さらに、この例では同じプロセスについて話しています。ファイルストリームのプロパティを別のファイルストリームから変更するのはあまり意味がありませんか?

たぶん、次の比較は、より良い、それを説明する:私の意見で

// works 
using (var fileStream1 = new FileStream("test.file", FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite)) 
using (var fileStream2 = new FileStream("test.file", FileMode.Append, FileAccess.Write, FileShare.Read)) 
using (var fileStream3 = new FileStream("test.file", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
{ 
} 

// fails 
using (var fileStream1 = new FileStream("test.file", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite)) 
using (var fileStream2 = new FileStream("test.file", FileMode.Append, FileAccess.Write, FileShare.Read)) 
using (var fileStream3 = new FileStream("test.file", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
{ 
} 

FileShare.Readの説明フレーズ:

は、読み取りのためのファイルのその後の開放を可能にします。

は、ファイルへのその後のアクセスは、すでに既存のロックのアクセスを含む読み取り、 のために制限されている

として読まれるべきです。

[更新]

私はコードを解析されていないが、これらの2つのリンクがコンストラクタの内部機能の上にいくつかの光を当てることができると思わ:

The internal FileStream ctor

The internal FileStream Init method

+0

あなたの答えを何度も読んでいるにもかかわらず、まだクリックされていません。私はAPIのドキュメントが完全に完全に間違っていると信じるのは難しいです。例えば。例えば、ファイルが開かれ、 'Read'が指定された場合、他のユーザーはファイルを読み込み用に開くことができますが、書き込み用に開くことはできません。それはまさに私の例でやろうとしたことですが、うまくいきません。 –

+0

@KentBoogaart:関連性があるかどうか分かりませんが(私も分かりません)、キーフレーズは「他のユーザー」かもしれません。 "他のユーザー"のより良いテストは、マルチスレッドテストになります。 – Chris

+0

@Chris:私の実際のシナリオはマルチスレッドです(バックグラウンド診断スレッドのログを収集しようとしています)。さらに、ドキュメントは、共有動作を記述するときに、「このプロセスまたは別のプロセスによって」と明示的に述べています。 –

1

私はCreateFileのドキュメントの答えを見つけたと思います。 dwShareModeパラメータの議論で

、それは言う:

FILE_SHARE_READ 0x00000001の は、読み取りアクセスを要求するために、ファイルやデバイス上で、その後のオープン操作を可能にします。 他のプロセスは、ファイルまたはデバイスが読み取りアクセスを要求すると、そのファイルまたはデバイスを開くことができません。 このフラグが指定されていないが、ファイルまたはデバイスが読み取りアクセス用に開かれている場合、関数は失敗します。

FILE_SHARE_WRITE 0x00000002 書き込みアクセスを要求するファイルまたはデバイスの後続のオープン操作を有効にします。 それ以外のプロセスは、書き込みアクセスを要求するとファイルまたはデバイスを開くことができません。 このフラグが指定されていないが、ファイルまたはデバイスが書き込みアクセス用に開かれているか、または書き込みアクセス付きのファイルマッピングがある場合、関数は失敗します。

これは、ファイル共有の仕組みを根本的に変更します。

関連する問題