PowerShell - Get-Content - CreateFile 将 dwShareMode 设置为 FILE_SHARE_READ | FILE_SHARE_WRITE
PowerShell - Get-Content - CreateFile sets dwShareMode to be FILE_SHARE_READ | FILE_SHARE_WRITE
是否有任何原因在使用 Get-Content -path file.txt 时,CreateFileW API 参数是:
dwDesiredAccess GENERIC_READ
dwShareMode FILE_SHARE_READ | FILE_SHARE_WRITE
lpSecurityAttributes NULL
dwCreationDisposition OPEN_EXISTING
dwFlagsAndAttributes FILE_FLAG_OPEN_NO_RECALL
如果我使用:
[System.IO.File]::ReadAllLines("file.txt")
dwDesiredAccess GENERIC_READ
dwShareMode FILE_SHARE_READ
lpSecurityAttributes NULL
dwCreationDisposition OPEN_EXISTING
dwFlagsAndAttributes FILE_FLAG_OPEN_NO_RECALL | FILE_FLAG_SEQUENTIAL_SCAN
为什么 FILE_SHARE_WRITE 设置为读取?有任何想法吗?谢谢
共享模式参数用于指示调用者可以接受哪些类型的共享并发访问 - Get-Content
正在使用 FILE_SHARE_READ | FILE_SHARE_WRITE
告诉操作系统“我不关心是否有人else 想在我持有此文件句柄时读取或写入文件。
这在连续跟踪日志文件时很重要,例如:
# imagine this is a log file
$tmpFile = New-TemporaryFile
$backgroundJob = Start-Job {
param([string]$LiteralPath)
1..10 |ForEach-Object {
"Log entry $_" |Add-Content @PSBoundParameters
Start-Sleep -Milliseconds 500
}
} -ArgumentList $tmpFile.FullName |Out-Null
# Tail the file and read the 10 log message as they roll in
$tmpFile |Get-Content -Wait |Select -First 10
$tmpFile |Remove-Item
如果你 运行 上面的代码,你会发现 Get-Content -Wait
能够连续读取文件,即使我们打开它并从后台作业写入它 10次.
如果未使用 FILE_SHARE_WRITE
.
打开基础文件句柄,这 不可能
为了观察这一点,让我们采用相同的示例并从使用 only FILE_SHARE_READ
:
打开的文件句柄中读取
$tmpFile = New-TemporaryFile
$backgroundJob = Start-Job {
param([string]$LiteralPath)
1..10 |ForEach-Object {
"Log entry $_" |Add-Content @PSBoundParameters
Start-Sleep -Milliseconds 500
}
} -ArgumentList $tmpFile.FullName
try {
# OpenRead() will open the file with SHARE_READ
$rfs = [System.IO.StreamReader]::new($tmpFile.OpenRead())
# Attempt to read the log lines, time out after 10 x 500ms
$c = 10
while(--$c){
$line = $rfs.ReadLine()
if($line -is [string]){
Write-Host $line
}
else{
# wait a little longer
Start-Sleep -Milliseconds 500
}
}
}
finally {
# clean up file reader
$rfs |ForEach-Object Dispose
$tmpFile |Remove-Item
}
# Fetch background job output, observe file access errors
$backgroundJob |Receive-Job -AutoRemoveJob -Wait
您应该会看到后台作业未能将消息记录到文件中,而不是在屏幕上显示日志消息:
The process cannot access the file 'C:\Users\irm\AppData\Local\Temp\tmpECB9.tmp' because it is being used by another
process.
+ CategoryInfo : WriteError: (C:\Users\irm\Ap...emp\tmpECB9.tmp:String) [Add-Content], IOException
+ FullyQualifiedErrorId : GetContentWriterIOError,Microsoft.PowerShell.Commands.AddContentCommand
+ PSComputerName : localhost
是否有任何原因在使用 Get-Content -path file.txt 时,CreateFileW API 参数是:
dwDesiredAccess GENERIC_READ
dwShareMode FILE_SHARE_READ | FILE_SHARE_WRITE
lpSecurityAttributes NULL
dwCreationDisposition OPEN_EXISTING
dwFlagsAndAttributes FILE_FLAG_OPEN_NO_RECALL
如果我使用: [System.IO.File]::ReadAllLines("file.txt")
dwDesiredAccess GENERIC_READ
dwShareMode FILE_SHARE_READ
lpSecurityAttributes NULL
dwCreationDisposition OPEN_EXISTING
dwFlagsAndAttributes FILE_FLAG_OPEN_NO_RECALL | FILE_FLAG_SEQUENTIAL_SCAN
为什么 FILE_SHARE_WRITE 设置为读取?有任何想法吗?谢谢
共享模式参数用于指示调用者可以接受哪些类型的共享并发访问 - Get-Content
正在使用 FILE_SHARE_READ | FILE_SHARE_WRITE
告诉操作系统“我不关心是否有人else 想在我持有此文件句柄时读取或写入文件。
这在连续跟踪日志文件时很重要,例如:
# imagine this is a log file
$tmpFile = New-TemporaryFile
$backgroundJob = Start-Job {
param([string]$LiteralPath)
1..10 |ForEach-Object {
"Log entry $_" |Add-Content @PSBoundParameters
Start-Sleep -Milliseconds 500
}
} -ArgumentList $tmpFile.FullName |Out-Null
# Tail the file and read the 10 log message as they roll in
$tmpFile |Get-Content -Wait |Select -First 10
$tmpFile |Remove-Item
如果你 运行 上面的代码,你会发现 Get-Content -Wait
能够连续读取文件,即使我们打开它并从后台作业写入它 10次.
如果未使用 FILE_SHARE_WRITE
.
为了观察这一点,让我们采用相同的示例并从使用 only FILE_SHARE_READ
:
$tmpFile = New-TemporaryFile
$backgroundJob = Start-Job {
param([string]$LiteralPath)
1..10 |ForEach-Object {
"Log entry $_" |Add-Content @PSBoundParameters
Start-Sleep -Milliseconds 500
}
} -ArgumentList $tmpFile.FullName
try {
# OpenRead() will open the file with SHARE_READ
$rfs = [System.IO.StreamReader]::new($tmpFile.OpenRead())
# Attempt to read the log lines, time out after 10 x 500ms
$c = 10
while(--$c){
$line = $rfs.ReadLine()
if($line -is [string]){
Write-Host $line
}
else{
# wait a little longer
Start-Sleep -Milliseconds 500
}
}
}
finally {
# clean up file reader
$rfs |ForEach-Object Dispose
$tmpFile |Remove-Item
}
# Fetch background job output, observe file access errors
$backgroundJob |Receive-Job -AutoRemoveJob -Wait
您应该会看到后台作业未能将消息记录到文件中,而不是在屏幕上显示日志消息:
The process cannot access the file 'C:\Users\irm\AppData\Local\Temp\tmpECB9.tmp' because it is being used by another
process.
+ CategoryInfo : WriteError: (C:\Users\irm\Ap...emp\tmpECB9.tmp:String) [Add-Content], IOException
+ FullyQualifiedErrorId : GetContentWriterIOError,Microsoft.PowerShell.Commands.AddContentCommand
+ PSComputerName : localhost