【发布时间】:2019-03-21 02:48:14
【问题描述】:
我有一个需要同时访问的 XML 文件。我不需要并发写入,但我确实需要并发读取。读取/修改此 XML 文件的规定方法是使用 PowerShell 脚本,该脚本使用 Linq to XML (XElement) 来处理 XML 文件。
理想的场景是:
- 团队中的所有用户都将在工作日开始时运行此 PowerShell 脚本,并将一直运行到工作日结束。
- 在整个工作日期间,团队中的任何用户都将输入预定义的命令,这些命令将查询 XML 文件以收集数据。每次用户运行其中一个查询时,它都会打开 XML 文件,执行查询,关闭 XML 文件,然后显示结果。
- 有时,这些用户中的任何一个都需要修改 XML 文件。用户将输入一个预定义的命令,指定他们想要修改的节点,然后他们将输入他们想要添加/修改的所有数据。然后脚本将打开文件(锁定它,因此其他用户无法以读/写方式打开它),将 XML 文件读入
XElement对象,执行所需的操作,然后将XElement保存回文件,然后释放锁。 - 在任何时候,当用户修改文件时(某些操作可能很长),任何其他尝试进行修改的用户不得能够打开文件(我会发现异常,并显示“请稍等”类型的消息)。但是,他们必须能够以只读方式打开文件才能执行查询。
我见过this related post, 'Concurrent file usage in C#',并尝试使用以下代码来实现这一点。在 PowerShell ISE 的一个实例中,我执行读写函数,然后在“输入项目名称”循环中,我在另一个 PowerShell ISE 实例中执行只读函数。尝试以只读方式打开文档时,我收到一条异常声明 The process cannot access the file 'C:\Path\To\file.xml' because it is being used by another process.
using namespace System.Linq.Xml
using namespace System.IO
Add-Type -AssemblyName 'System.Xml.Linq (rest of Assembly's Full Name)'
$filename = "C:\Path\To\file.xml"
function Read-Only()
{
$filestream = [FileStream]::new($filename, [FileMode]::Open, [FileAccess]::Read)
$database = [XElement]::Load($filestream)
foreach($item in $database.Element("Items").Elements("Item"))
{
Write-Host "Item name $($item.Attribute("Name").Value)"
}
$filestream.Close()
$filestream.Dispose()
}
function Read-Write()
{
$filestream = [FileStream]::new($filename, [FileMode]::Open, [FileAccess]::ReadWrite, [FileShare]::Read)
$database = [XElement]::Load($filestream)
$itemname = Read-Host "Enter an item name ('quit' to quit)"
while($itemname -ne 'quit')
{
$database.Element("Items").Add([XElement]::new([XName]"Item", [XAttribute]::new([XName]"Name", $itemname)))
$itemname = Read-Host "Enter an item name ('quit' to quit)"
}
$filestream.Seek(0, [SeekOrigin]::Begin)
$database.Save($filestream)
$filestream.Close()
$filestream.Dispose()
}
如何锁定文件以进行独占编辑,同时仍允许对任何其他客户端进行只读访问?
编辑:我已经通过使用 mklement0 建议的解决方案解决了这个问题 - 使用单独的文件作为锁定文件。代码贴在这里:https://pastebin.com/ytzGE7se
【问题讨论】:
-
为什么不在编辑前修改 ACL 并在最后重置?
-
这似乎有点笨拙,尤其是看到有可能在不修改 ACL 的情况下做到这一点?
标签: c# .net xml powershell linq-to-xml