【问题标题】:File in use with .net method but not with powershell cmdlet使用 .net 方法但不使用 powershell cmdlet 的文件
【发布时间】:2018-07-31 16:43:45
【问题描述】:

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

Get-Content $path

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

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

“进程无法访问文件‘XYZ’,因为它正被 另一个进程。”

Q1:为什么 .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
}

Author to original code on StackOverflow

非常感谢任何帮助!

PS!我正在使用 powershell 2.0 并且无法终止正在使用该文件的进程。我也没有文件的写权限,只能读。

【问题讨论】:

    标签: .net powershell powershell-2.0


    【解决方案1】:

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

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

    这就是Get-Content(总是)在幕后所做的事情,这就解释了为什么当你使用它时问题不会出现

    相比之下,[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 中这些 .net 方法的更多信息?我发现的是针对 .net 本身的,因此使用不同的语法,并且 PS 并不支持所有内容。
    • @Ajama:很高兴。我知道的唯一文档是Get-Help about_Methods。有一些陷阱和限制,但您应该能够从 PowerShell 调用大多数 .NET 方法。不幸的是,.NET 文档没有提供切换到 PowerShell 语法的功能(您只能在 C#、VB、F# 和 C++ 中进行选择),因此您将根据了解 PowerShell 的语法自行解决。
    【解决方案2】:

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

    Official docs

    从文件或其他项目的末尾获取指定数量的行。
    此参数在 Windows PowerShell 3.0 中引入。
    您可以使用“Tail”参数名称或其别名“Last”。

    【讨论】:

      猜你喜欢
      • 2021-02-11
      • 2016-10-06
      • 1970-01-01
      • 2016-01-17
      • 2017-09-17
      • 2021-09-30
      • 2012-04-26
      • 2017-09-07
      • 1970-01-01
      相关资源
      最近更新 更多