2017-02-17 168 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行为。