2017-02-17 15 views
2

デスクトップのWindowsストアアプリを開発しようとすると、レンガの壁にぶつかったようです。私は、別のアプリケーションが開いている大きな(100 MB以上の)ログファイルを開いて、ファイルに書き込まれている最新のイベントをリアルタイムで処理しようとしています。定期的に、非サンドボックスのC#でUWP - 別のアプリケーションが開いている場合にファイルを開くことができません

が、これは非常に簡単です:私は別のアプリケーションで使用中のファイルを開こうとするたび

System.IO.FileStream stream = File.Open("LOGFILE PATH HERE", System.IO.FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 

は残念ながら、UWPで、私は「UnauthorizedAccessException」を取得します。私は見つけることができるすべての組み合わせですべてのAPIを試しましたが、運がなかったので、ここでいくつかの提案をしてきました。

私が試したことのいくつか:

Windows.Storage.Pickers.FileOpenPicker picker = new Windows.Storage.Pickers.FileOpenPicker(); 
picker.ViewMode = Windows.Storage.Pickers.PickerViewMode.List; 
//Prompt the user to open the log file: 
Windows.Storage.StorageFile logFile = await picker.PickSingleFileAsync(); 
picker.FileTypeFilter.Add(".txt"); 

//This won't work in any case, because it doesn't use the handle that the user picked, 
// so the UWP sandboxing blocks it: 
new FileStream(logFile.Path, FileMode.OpenOrCreate, FileAccess.Read); 

//EDIT: These don't work if the file is open either, I must have made a mistake earlier 
await FileIO.ReadBufferAsync(logFile); 
await FileIO.ReadLinesAsync(logFile); 

//These work if the file is not open by another app, but fail if another app has the file open 
await logFile.OpenAsync(Windows.Storage.FileAccessMode.Read); 
await logFile.OpenStreamForReadAsync(); 

クイックリプロ:

オープンPowerShellウィンドウ、および自分のホームディレクトリにオープン "のtest.txt" を開催するには、次のコマンドを実行します。

+0

この投稿を参照してください:http://stackoverflow.com/questions/4400517/how-can-i-read-a-file-even-when-getting-an-in-use-by-another-process -exception – Sparrow

+0

これは非UWPアプリケーションの場合のみです。この場合は動作しません。これが私が試した最初のものです。私のコメントではうまくいかなかったことの例として、このコードがあります。*( –

+0

Man、これは欲求不満です.. System.Diagnostics.Stopwatchによると、ReadBufferAsyncは100MBのログファイルを100ms読み込みます。 SSDを搭載した超高速のdevマシンでは、実際にはファイル全体がバッファリングされているようです。 一方、まだ開かれていないファイルでは、StorageAsFileのOpenAsync(...)メソッドは2ms以下です。 。Fiddlesticks !!! –

答えて

0

私は簡単なテストを行いました。これはうまくいくはずです。テストは次のようになります: - メモ帳でfile.txtを開くと、ファイルには1行のテキストしか含まれません - アプリケーションは のコードで実行します - まだメモ帳で開いているファイルを選択してください、 最初の行をデバッグ出力に表示し、空の秒を参照してください。

コード:上記のコードはawait Task.Delay()に当たっている間、私は、メモ帳でファイルを修正し、それを保存している第二の試験で

public async Task GetFile() 
{ 
    Windows.Storage.Pickers.FileOpenPicker picker = new Windows.Storage.Pickers.FileOpenPicker(); 
    picker.ViewMode = Windows.Storage.Pickers.PickerViewMode.List; 
    picker.FileTypeFilter.Add(".txt"); 
    //Prompt the user to open the log file: 
    Windows.Storage.StorageFile logFile = await picker.PickSingleFileAsync(); 

    try 
    { 
     using (var stream = await logFile.OpenStreamForReadAsync()) 
     using (var reader = new StreamReader(stream)) 
     { 
      var line = await reader.ReadLineAsync(); 
      Debug.WriteLine($"The first line: {line} - waiting"); 
      await Task.Delay(10000); 
      line = await reader.ReadLineAsync(); 
      Debug.WriteLine($"The next line: {line} - waiting"); 
     } 
    } 
    catch (Exception exc) 
    { 
     Debug.WriteLine($"Exception {exc.Message}"); 
    } 
} 

、二行目を読み取ろうとするときに、あなたはおそらく取得します。 '例外このoplockに関連付けられているハンドルが閉じられました。 oplockは現在壊れています。 '。

ストリームを廃棄していないことがわかりました。おそらく問題はここにありますか?あなたはのためにusingを使いこなそうとしましたか?Idisposable

+0

Romaszありがとう。私はあなたが提供した例を試しましたが、私がメモ帳で開いたドキュメントではうまくいきますが、別のアプリケーション(またはPowerShell)を使って開いていると、UnauthorizedAccessExceptionがスローされます。 私はC#初心者ですが、どのようにそのタスクを実行する必要がありますか?私はボタンイベントハンドラを作って、単に "await GetFile()"と呼んだ。 オリジナルの投稿を編集して、ファイルを開いたままにしているpowershellコマンドを追加します。これは、大規模なロギングアプリの動作を複製するようです。 –

+0

@DebugArnaut他のアプリやPowerShellで試したことがありますか?スタンドアローンまたはビジュアルスタジオ内のPowershell? – Romasz

2

これは、Anniversary Updateの時点でのUniversal APIの予想される動作です。 (別名RS1)。 Windows.Storage。* APIとストリームは、 "Polite Reader"モデルと呼ばれるものを使用します。このモデルでは、OPLOCKブレーク・エラーを生成するライターによって読者を中断することができます。 RS1では、これは、書き込み用のオープンハンドルがすでに存在する場合に、リーダーがブロックされることを意味します。

クリエイターアップデート(別名RS2)では、これでいくつかの変更があります。ユニバーサルプラットフォームが単一のフォアグラウンドアプリケーションで元のWinRTから進化したので、アプリケーションがより伝統的なモデルを使用できるようにする必要性が生じました。したがって、RS2ではこのシナリオで役立ついくつかの変更を行っています。作家が既に存在する場合

  1. 修飾されていない丁寧なリーダーは、もはやオープンに失敗します。ただし、ライターが実際にファイルに書き込む場合、読者はoplockブレークを取得します。
  2. 共有違反は、AccessDeniedに変換されるのではなく、発信者に直接表示されます。(互換性のため、アプリケーションのマニフェストでテストされたプラットフォームとしてRS2を宣言する呼び出し側のアプリケーションでこの新しい動作がゲートされます)
  3. 新しいStorageOpenOptionsが利用可能になりました。効果的にOpLockの動作を選択しないようにします。
関連する問題