使用 .net 方法但不使用 powershell cmdlet 的文件

File in use with .net method but not with powershell cmdlet

要在 powershell 中打开和读取文件,我使用以下两种方法之一:

Get-Content $path

[System.IO.File]::OpenRead($path)

在读取另一个进程正在使用的日志文件时,Get-Content 似乎没有任何问题。然后,与 .NET 方法相比,powershell cmdlet 速度较慢并且使用更多内存。但是,当我尝试使用 .NET 方法时,出现以下错误:

"The process cannot access the file 'XYZ' because it is being used by another process."

问题 1:为什么 .net 方法不能访问文件而 powershell cmdlet 可以?

Q2:如何使用.net方式读取文件?由于 Get-Content 对于大约 80 MB 的日志文件来说太慢了。我通常只读最后一行:

$line = ""
$lineBreak = Get-Date -UFormat "%d.%m.%Y "
$bufferSize = 30
$buffer = New-Object Byte[] $bufferSize
$fs = [System.IO.File]::OpenRead($logCopy)
while (([regex]::Matches($line, $lineBreak)).Count -lt $n) {
    $fs.Seek(-($line.Length + $bufferSize), [System.IO.SeekOrigin]::End) | Out-Null
    $fs.Read($buffer, 0, $bufferSize) | Out-Null
    $line = [System.Text.Encoding]::UTF8.GetString($buffer) + $line
}
$fs.Close()

    ($line -split $lineBreak) | Select -Last $n
}

非常感谢任何帮助!

PS!我使用的是 powershell 2.0,无法终止正在使用该文件的进程。另外我没有文件的写入权限,只能读取。

PetSerAl,像往常一样,提供了一个简洁的评论,提供了一个有效的解决方案并暗示了一个解释:

要防止 "The process cannot access the file 'XYZ' because it is being used by another process." 错误,您必须使用共享模式 FileShare.ReadWrite 打开文件,以便其他想要 写入 [=39] 的进程=] 文件不会被拒绝访问。

这就是 Get-Content(总是)在幕后所做的事情,这解释了为什么当您使用 it.

时问题不会浮出水面

相比之下,[System.IO.File]::OpenRead() 默认为共享模式 FileShare.Read,这意味着其他进程可以 读取 ,但不能写入同一文件。

因此,请改用 [System.IO.File]::Open(),它允许您明确指定共享模式:

$fs = [IO.File]::Open($path, 
                  [IO.FileMode]::Open, 
                  [IO.FileAccess]::Read, 
                  [IO.FileShare]::ReadWrite)
# ...
$fs.Close()

请注意,我在上面的类型名称中省略了 System. 部分;此组件在 PowerShell 中始终是可选的。

如果您可以移动到更高版本的 PowerShell(至少 v3.0),那么 Get-Content -Tail 是一个不错的选择。我们广泛使用它并且性能适合我们的场景。

Official docs

Gets the specified number of lines from the end of a file or other item.
This parameter is introduced in Windows PowerShell 3.0.
You can use the "Tail" parameter name or its alias, "Last".