55

テスト ベンチの一部として使用している .csv ファイルがいくつかあります。ファイルを Excel で開いていない限り、問題なく開いて読むことができます。その場合は、次のようになりIOExceptionます。

System.IO.IOException : 別のプロセスで使用されているため、プロセスはファイル 'TestData.csv' にアクセスできません。

これは、テスト ベンチからの抜粋です。

using (CsvReader csv = new CsvReader(new StreamReader(new FileStream(fullFilePath, FileMode.Open, FileAccess.Read)), false))
{
    // Process the file
}

これは StreamReader の制限ですか? 他のアプリケーション (Notepad++ など) でファイルを開くことができるので、O/S の問題にはなりません。たぶん、他のクラスを使用する必要がありますか?誰かがこれを回避する方法を知っていれば(Excelを閉じることは別として!)、とても感謝しています。

4

5 に答える 5

165

Jared が言うように、ファイルを開いている他のエンティティが共有読み取りを許可しない限り、これを行うことはできません。Excel では、書き込み用に開いているファイルであっても、共有読み取りが可能です。したがって、FileShare.ReadWriteパラメーターを使用してファイル ストリームを開く必要があります。

FileShare パラメータはよく誤解されています。ファイルの他のオープナーができることを示します。これは、過去のオープナーだけでなく、将来のオープナーにも適用されます。FileShare は、以前のオープナー (Excel など) に対する遡及的な禁止ではなく、現在のオープンまたは将来のオープンで違反してはならない制約と考えてください。

現在ファイルを開こうとしている場合、FileShare.Read は、「以前のオープナーが読み取り専用で開いた場合にのみ、このファイルを正常に開いてください」と言います。Excel によって書き込み用に開かれているファイルに FileShare.Read を指定すると、 Excel が書き込み用に開いているため、制約に違反するため、ファイルを開くことができませ

Excel では書き込み用にファイルが開かれているため、正常に開くには、FileShare.ReadWrite を使用してファイルを開く必要があります。FileShare パラメーターのもう 1 つの考え方は、「他のユーザーのファイル アクセス」を指定することです。

ここで、現在他のアプリで開かれていないファイルを開くという別のシナリオを考えてみましょう。FileShare.Read は、「将来のオープナーは読み取りアクセスでのみファイルを開くことができます」と述べています。

論理的には、これらのセマンティクスは理にかなっています。FileShare.Read は、他の人が既にファイルを書き込んでいる場合はそのファイルを読みたくないことを意味し、既に読んでいる場合は他の人にファイルを書きたくないことを意味します。FileShare.ReadWrite は、別の人がファイルを書き込んでいる場合でも、ファイルを読み取る意思があることを意味し、読み取り中に別のオープナーにファイルを書き込んでも問題ありません。

これにより、複数のライターが許可されることはありません。FileShare は、データベースの IsolationLevel に似ています。ここでの望ましい設定は、必要な「一貫性」の保証によって異なります。

例:

using (Stream s = new FileStream(fullFilePath, 
                                 FileMode.Open,
                                 FileAccess.Read,
                                 FileShare.ReadWrite))
{
  ...
}

また、

using (Stream s = System.IO.File.Open(fullFilePath, 
                                      FileMode.Open, 
                                      FileAccess.Read, 
                                      FileShare.ReadWrite))
{
}

補遺:

System.IO.FileShare に関するドキュメントは、少し簡潔です。正確な事実を知りたい場合は、Win32 CreateFile 関数のドキュメントを参照してください。FileShare の概念がよりよく説明されています。

于 2009-05-22T14:05:09.143 に答える
16

編集

なぜこれが答えなのかはまだ 100% わかりませんが、FileShare.ReadWrite を FileStream コンストラクターに渡すことでこの問題を解決できます。

using (CsvReader csv = new CsvReader(new StreamReader(new FileStream(fullFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)), false)
{
  ...
}

私の好奇心は今のところ私を捉えており、なぜこれが特定の答えなのかを理解しようとしています. 後でわかったら、その情報でこれを更新します。

最良のドキュメントは、実際にはCreateFile関数にあるようです。これは、ファイルを開くために .Net が内部で呼び出す関数です (ファイルの作成は少し誤称です)。ファイルを開くという共有の側面がどのように機能するかについてのより良いドキュメントがあります。別のオプションは、Cheesoの答えを読むことです

于 2009-05-22T13:22:00.603 に答える
5

別のプロセスがファイルを開いている場合は、多くの場合、File.Copy を使用してからコピーを開くことができます。エレガントなソリューションではなく、実用的なソリューションです。

于 2009-05-22T13:25:04.250 に答える
0

もう 1 つの注意点は、 で を開く場合FileStreamFileShare.ReadWriteそのファイルを次に開くときにも を指定する必要がありますFileShare.ReadWrite。そうしないと、「別のプロセスがこのファイルを使用しています」というエラーが表示されます。

于 2012-10-05T04:34:41.867 に答える
-7

System.Diagnostics の使用;

Process.Start(“filename&Path”) を呼び出すだけです。

それが役立つかどうかはわかりませんが、イントラネットにプレビュー PDF ボタンを実装するために使用したものです。

于 2012-11-29T13:16:30.413 に答える