首页 文章

UWP - 如果另一个应用程序打开文件,则无法打开文件进行读取

提问于
浏览
3

2018 EDIT: 如下所示和其他来源,以Creator的更新或更高版本为目标,允许对另一个进程打开以供写入的文件进行只读文件访问 . 万岁!

在尝试为桌面开发Windows应用商店应用时,我似乎遇到了困难 . 我正在尝试打开另一个应用程序已打开的大型(100 MB)日志文件,并在将最新事件写入文件时对其进行实时处理 .

使用常规的非沙盒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();

Quick Repro:

打开PowerShell窗口,然后运行此命令以在主目录中保持打开“test.txt”:

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

2 回答

  • 1

    这是周年纪念更新中Universal API的预期行为 . (又名RS1) . Windows.Storage . * API和流使用所谓的“礼貌读者”模型 . 在此模型中,读取器可能会被写入器中断,从而生成OPLOCK中断错误 . 在RS1中,这也意味着如果已存在任何打开的写入句柄,则会阻止读者 .

    在创作者更新(又名RS2)中,有些事情正在发生变化 . 随着通用平台从最初的WinRT发展而来,只需一个前台应用程序,就需要允许应用程序使用更传统的模型 . 因此,在RS2中,我们进行了一些更改以帮助在这种情况下 .

    • 如果作家已经存在, Unmodified 礼貌读者将不再在打开时失败 . 但是,如果编写器实际写入文件,读者仍将获得oplock中断 .

    • 共享冲突直接显示给调用者,而不是转换为AccessDenied . (为了兼容性,这个新行为在调用应用程序上被门控,声明RS2作为应用程序清单中的测试平台)

    • 有新的StorageOpenOptions可用,以便应用程序可以更改其代码以使用新选项来获取不涉及oplock的行为,从而有效地选择退出OpLock行为 .

  • 3

    我做了一个简单的测试,它应该工作 . 测试结果如下: - 使用记事本打开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() ,然后在尝试读取第二行时,您可能会得到:'Exception与此oplock关联的句柄已关闭 . oplock现在坏了 . '

    我看到你没有处理流,也许问题在这里?您是否尝试过 using 用于Idisposable?

相关问题