2017-02-17 140 views
2

嘗試爲桌面開發Windows應用商店應用程序時,我似乎遇到了困難。我試圖打開另一個應用程序已打開的大型(100+ MB)日誌文件,並在寫入文件時對最新事件進行實時處理。UWP - 如果其他應用程序打開文件,則無法打開文件

通過定期,非沙盒C#中,這是非常簡單的:

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」:

$f = [System.IO.File]::Open("test.txt", [System.IO.FileMode]::OpenOrCreate, [System.IO.FileAccess]::Write, [System.IO.FileShare]::ReadWrite); 
+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也需要100ms才能讀取一個適中的100MB日誌文件同時,對於尚未打開的文件,StorageFile的OpenAsync(...)方法需要2ms以下的時間,所以它正是我需要的。Fiddlesticks !!! –

回答

0

我做了一個簡單的測試,它應該工作。測試如下: - 用記事本打開一個file.txt文件,該文件只包含一行文本, - 用下面的代碼運行應用程序, - 選擇一個仍在記事本中打開的文件, - 應該在調試輸出中看到第一行和空的第二行。

代碼:

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}"); 
    } 
} 

在第二次測試我在記事本修改該文件並保存它,而上面的代碼打await Task.Delay(),然後試圖讀取第二行的時候,你可能會得到: '異常與此關聯的手柄已關閉。這塊手錶現在壞了。'。

我看到你沒有處理流,也許問題出在這裏?您是否嘗試過使用using作爲Idisposable

+0

感謝Romasz。我嘗試了OpenStreamForReadAsync,並且它不起作用我剛剛試用了你提供的例子,它對我在記事本中打開的文檔起作用,但是如果我使用另一個應用程序(或PowerShell)將其打開,它將引發UnauthorizedAccessException 。 雖然我是一個C#新手,我該如何執行該任務?我創建了一個按鈕事件處理程序,並將其命名爲「await GetFile()」。 我會編輯我的原始帖子,添加我用來保存打開的文件的powershell命令,這似乎重複了大型日誌記錄應用程序的行爲。 –

+0

@DebugArnaut您是否嘗試過使用其他應用程序或PowerShell? Powershell獨立或在視覺工作室? – Romasz

2

這是週年紀念更新通用API的預期行爲。 (又名RS1)。 Windows.Storage。* API和流使用所謂的「有禮讀者」模式。在這個模型中,讀者可以被作家打斷,這會產生OPLOCK中斷錯誤。在RS1中,這也意味着如果已經存在任何用於寫入的打開句柄,則讀取器被阻止。

在創作者更新(又名RS2)中,有些事情正在改變。隨着通用平臺從最初的WinRT演變爲單一的前臺應用程序,需要允許應用程序使用更傳統的模型。因此,在RS2中,我們正在做一些改變來幫助解決這種情況。

  1. 未修改有禮貌閱讀器將不再開放失敗,如果一個作家已經存在。但是,如果作者實際寫入文件,讀者仍然會得到oplock中斷。
  2. 共享衝突直接顯示給調用者,而不是翻譯成AccessDenied。(爲了兼容性,這種新行爲在呼叫應用程序上被屏蔽,聲明RS2是應用程序清單中的測試平臺)
  3. 有新的StorageOpenOptions可用,因此應用程序可以更改其代碼以使用新選項來獲取行爲不涉及oplocks,有效地選擇OpLock行爲。