【发布时间】:2018-12-17 05:55:06
【问题描述】:
我正在尝试通过在多台机器上同时运行的多个进程在 XML 文件中实现信息更新。我的想法是循环 10 分钟,尝试打开和锁定文件以随机间隔最多 1 秒写入。文件打开并锁定后,我会加载所有 XML,添加当前机器的信息,对 XML 进行排序,然后转售并移除锁定,以便下一台机器可以打开。问题是 Get-Content 不会锁定文件,因此两台机器可以加载相同的 XML,而不是第二台机器使用来自第一台的数据加载 XML。 我找到了this,它提供了一种锁定文件的方法,然后通过流读取,但是当我尝试修改为这个时
$file = [IO.File]::Open($path, 'Open', 'ReadWrite', 'None')
$xml = Get-Content $path
我收到一个错误,因为文件被锁定。似乎 Get-Content 没有锁定文件,但它确实尊重已经存在的锁。 那么,有没有办法锁定文件,只有机器锁定才能读写? 也许更重要的是,这是否是正确的方法,还是有其他方法可以访问多个 XML?这似乎是一种常见的情况,因此必须有一些最佳实践方法来做到这一点,即使没有本机 cmdlet 方法。 FWIW,我必须支持回到 PowerShell 2.0,这无疑限制了我如何解决这个问题。
编辑:好吧,[io.file] 位中的第三个参数的 Read 似乎不起作用。 我现在有了这个
$path = '\\Px\Support\Px Tools\Resources\jobs.xml'
foreach ($i in 1..10) {
$sleepTime = get-random -minimum:2 -maximum:5
$file = [IO.File]::Open($path, 'Open', 'ReadWrite', 'Read')
[xml]$xml = Get-Content $path
$newNode = $xml.createElement('Item')
$newNode.InnerXml = "$id : $i : $sleepTime : $(Get-Date)"
$xml.DocumentElement.AppendChild($newNode) > $null
$xml.Save($path)
$file.Close()
}
理论上应该采用我拥有的 XML,带有两个虚拟日志项,读取它,附加另一个日志项(带有 ID、迭代、睡眠时间和时间戳)并重复 10 次,随机睡眠之间。它会在床上大便,试图用
保存"The process cannot access the file '\\Px\Support\Px Tools\Resources\jobs.xml' because it is being used by another process."
我真的在尝试做之前没有做过 1000 次的事情吗?
好的,根据 cmets,这就是我所在的位置。我想确保在处理过程中不能(轻松)手动编辑原件。所以我已经实现了这个。 1:查找哨兵文件,如果没有找到 2:锁定原始文件,使其无法修改 3:复制原件为哨兵文件 4:根据需要修改sentinel文件 5:解锁原版 6:将哨兵文件复制到原始文件上 7:删除哨兵
在我看来,不确定的一点是如果有人在解锁它和哨兵被复制之间手动修改了原件,这是极不可能的。但是,似乎应该有一种方法可以 100% 确定地处理这个问题,我想不出有没有哨兵文件的方法。
【问题讨论】:
-
下面的答案现在向您展示了如何在没有哨兵文件的情况下做到这一点。您描述的哨兵文件方法否定了使用哨兵文件的好处 - 请使用概述的算法@ 987654322@,关键部分是如何声明哨兵文件以避免竞争条件,并且在新的之前不获得排他锁内容已准备好替换文件。
-
问题是文件被锁定后才能准备新内容。我正在读取文件的当前内容,添加,排序,然后保存。所以我需要先锁定然后再阅读,所以我可以确定,当我添加新信息时,不会添加任何其他信息。我有一些似乎正在工作的东西。是时候查看下面的信息了,看看这些信息如何影响我所拥有的任何变化。
-
是的,如果您使用所有进程都尊重的哨兵文件,您可以将准备工作分开,如链接答案中所述 - 这是使用哨兵文件。如果您不介意在准备任务期间也专门锁定您的文件,那么下面的答案应该可以。
标签: xml powershell concurrency