【发布时间】:2020-01-14 14:43:08
【问题描述】:
我的脚本通常假设存在一个 *.txt 文件,并设置了帮助它更好地运行的设置。但是,如果脚本不存在,它会创建一个本地文件来保存这些设置。我意识到没有逻辑需要然后读取此文件,但我想了解为什么我不能。
[void][System.IO.File]::Create($PSFileName)
$ReadPS = New-Object System.IO.StreamReader($PSFileName)
在脚本可能(很少)创建文件后,它会立即尝试读取它,这会产生以下错误:New-Object : Exception calling ".ctor" with "1" argument(s): "The process cannot access the file 'C:\Temp\MyFile.txt' because it is being used by another process."
所以我必须等待文件可用,对吗?然而,简单的 5s 开始睡眠是行不通的。但是,如果我用 try-catch 将它包装在一个循环中,它每次都会在几分之一秒内工作:
[void][System.IO.File]::Create($PSFileName)
$RCount = 0 # if new file created, sometimes it takes a while for the lock to be released.
Do{
try{
$ReadPS = New-Object System.IO.StreamReader($PSFileName)
$RCount+=100
}catch{ # if error encountered whilst setting up StreamReader, try again up to 100 times.
$RCount++
Start-Sleep -Milliseconds 1 # Wait long enough for the process to complete. 50ms seems to be the sweet spot for fewest loops at fastest performance
}
}Until($RCount -ge 100)
$ReadPS.Close()
$ReadPS.Dispose()
这太令人费解了。为什么文件会在任意时间保持锁定状态,而我等待的时间似乎越长?我可以在文件创建和 StreamReader 之间调整或添加什么以确保文件可用吗?
【问题讨论】:
-
如果我运行您的创建代码,然后在该文件上运行
Get-Content,我会收到一条红色错误文本,上面写着Get-Content : The process cannot access the file 'C:\Temp\Testing.txt' because it is being used by another process。如果我连续进行 3 次调用,则第 1 次失败,但第 2 次和第 3 次显示没有错误。如果我在第一次 G-C 调用之前添加Start-Sleep,我会收到一个错误。 ///// 我怀疑这是因为整个脚本停止了 5 秒......并且文件句柄在脚本停止时保持打开状态。这似乎与您的 try/catch 解决方案一致...... -
File.Create生成一个由FileStream封装的打开文件句柄。如果您不处置它,那将导致锁定冲突(尽管您,原始进程打开了它)。使用[System.IO.File]::Create($PSFileName).Dispose(),或(更高级一点)$null | Out-File $PSFileName -Encoding ascii。 -
另一种供您批准的选择,以防
Out-File有点太晦涩:[System.IO.File]::WriteAllBytes($PSFileName, @())。请注意,如果文件已经存在,this 和Out-File都会截断该文件;如果这是不可取的,请使用-Append为Out-File和AppendAllText($PSFileName, "")为File(奇怪的是,没有File.AppendAllBytes方法)。 -
愚蠢的问题:为什么我们需要在已知的空文件上使用 StreamReader?我想任何后续答案都可以在 System.IO 下的某处使用写入功能......同样容易。只是想我会指出来......
-
@Steven - 基本上,我花了一段时间重构我的所有代码,以最符合逻辑的“ifs”和“whiles”顺序运行,最后,99%它获取现有配置文件的时间。作为最后的冗余步骤,如果无法获取该文件,我将创建该文件。在所有这些工作之后,无论它是否是一个空的配置文件,运行相同的文件读取步骤都会非常好。我可以添加额外的逻辑来省略该步骤或确保它成功发生,但“感觉”明智的做法是找出它被锁定的原因并避免错误。