Search code examples
c#uwpwindows-store

UWP - Can't open file for reading if another application has it open


2018 EDIT: As indicated below and by other sources, targeting the Creator's Update or higher allows for read-only file access of a file opened for write by another process. Hooray!

I seem to have hit a brick wall when trying to develop a Windows Store app for the desktop. I'm trying to open a large (100+ MB) log file that another application has open and do real time processing on the latest events as they're written to the file.

With regular, non-sandboxed C#, this is pretty straightforward:

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

Unfortunately, in a UWP, I get "UnauthorizedAccessException" whenever I try to open a file that's in use by another app. I've tried every API in every combination I could find, but have had zero luck, so I've come here for some suggestions.

Some of what I've tried:

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();

Quick Repro:

Open a PowerShell window, and run this command to hold open "test.txt" in your home directory:

$f = [System.IO.File]::Open("test.txt", [System.IO.FileMode]::OpenOrCreate, [System.IO.FileAccess]::Write, [System.IO.FileShare]::ReadWrite);

Solution

  • This is expected behavior for the Universal APIs as of the Anniversary Update. (aka RS1). The Windows.Storage.* APIs and streams use what is called a "Polite Reader" model. In this model readers can be interrupted by a writer, which generates the OPLOCK break errors. In RS1 this also means that readers are blocked if ANY open handle for write exists already.

    In the Creators Update (aka RS2) some things are changing on this. As the Universal Platform evolved from the original WinRT with a single foreground app, the need to allow apps to use more traditional models arose. Thus, in RS2 we are making a few changes to help in this scenario.

    1. An Unmodified polite reader will no longer fail on open if a writer already exists. However, readers will still get oplock breaks if the writer actually writes to the file.
    2. Sharing Violations are surfaced directly to the caller instead of being translated into AccessDenied. (For compatibility, this new behavior is gated on the calling app declaring RS2 as the tested platform in the apps’ manifest)
    3. There are new StorageOpenOptions available so that apps can change their code to use the new options to get behavior that doesn’t involve the oplocks, effectively opting out of the OpLock behavior.