【问题标题】:In .Net, Is there a way to get [System.IO.File]::ReadAllLines($file) to read a partially locked file?在 .Net 中,有没有办法让 [System.IO.File]::ReadAllLines($file) 读取部分锁定的文件?
【发布时间】:2022-01-26 07:32:54
【问题描述】:

在 powershell 中,“Get-Content (filename)”命令在读取锁定为只读模式写入的文件时没有任何问题。

那么为什么我不能使用 PowerShell 中的 .net 函数 ReadAllLines 来做同样的事情呢?我不明白为什么 ReadAllLines() 会比 Get-Contents 更具侵入性?它所做的只是读取文件的内容,然后将其关闭。

无论如何,我更喜欢使用 .net 函数而不是本机 powershell 函数,因为它们不太混乱,除了 ReadAllLine 对于部分锁定的文件无法正常工作......有没有办法让 ReadAllLines .net 在读取部分锁定的文件时与 Get-Content 的工作方式相同...可以读取但锁定写入的文件?

[Collections.Generic.List[string]]$lines  = [System.IO.File]::ReadAllLines($file)

诗句:

$arr1   = Get-Content $file
$lines  = [Collections.Generic.List[string]]$arr1

【问题讨论】:

  • 调用[System.IO.File]::ReadAllLines($file) 时会发生什么?如果抛出错误,请完整发布错误消息
  • 使用“1”参数调用“ReadAllLines”的异常:“进程无法访问文件 'C:\Users\wpmoore\Desktop\collins\sandbox\sandbox.vsc.tbwork\out .sim\xsim.log',因为它正被另一个进程使用。”在 H:\tools\scripts\filter_xsimlog.ps1:26 char:1 + [Collections.Generic.List[string]]$lines = [System.IO.File]::ReadAll ... + ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : IOException
  • Get-Content 没有问题...但是...
  • 似乎有人应该向 .net 人员提交一个错误,以重写 readalllines 代码,使其与从 powershell 获取内容的工作相同,并且不会抛出具有部分锁定访问权限的异常......
  • 非常有趣。我可以通过之前打开同一个文件的可写流来重现您在使用ReadAllLines() 时遇到的错误 - 但在这种情况下,Get-Content 对我来说失败了......

标签: .net powershell


【解决方案1】:

我设法在 Windows PowerShell 5.1 中重现了这种行为,如下所示:

using namespace System.IO

# open writable file stream
$writeLocker = [FileStream]::new($file, [FileMode]::Open, [FileAccess]::Write)

# Get-Content can still read file contents (this doesn't throw)
Get-Content $file |Out-Null

# But this fails because another process owns a conflicting file handle
[File]::ReadAllLines($file)

这是因为ReadAllLines() 总是请求对目标文件进行只读访问 - 这与已经打开的可写文件句柄冲突,因此打开文件的尝试失败。

文件系统提供程序需要只读访问权限,因此Get-Content 在没有独占访问权限的情况下读取文件没有问题。

如果您真的想要,您可以通过在读写共享模式下打开文件流自己使用 BCL 类来模拟此行为(表明调用者不在乎是否有人已经拥有文件的读取和/或写入权限):

using namespace System.IO

class PicoFile
{
  static [string[]] ReadAllLines([string]$path)
  {
    $file = Get-Item -LiteralPath $path

    # request read-access but indicate sharing for read-write purposes are acceptable
    $fileStream = [FileStream]::new($file.FullName, [FileMode]::Open, [FileAccess]::Read, [FileShare]::ReadWrite)
    try {
      $fileReader = [StreamReader]::new($fileStream, [Text.Encoding]::Utf8)
      try {

        # keep reading lines from the file until there are no more lines    
        [string[]]$lines = while($null -ne ($line = $fileReader.ReadLine())){ $line }

        return $lines
      }
      finally {
        $fileReader |ForEach-Object Dispose
      }
    }
    finally {
      $fileStream |ForEach-Object Dispose
    }
  }
}

...但我强烈建议您坚持使用Get-Content :-)

【讨论】:

  • 我正在查看 this answer 以获得相同的提示,未经测试,但 [System.IO.File]::OpenRead(...) + [System.IO.StreamReader]::new($handle).ReadToEnd() 可能也有效
  • @SantiagoSquarzon 同样的问题,OpenRead() 也需要只读权限
  • 很高兴知道,谢谢
猜你喜欢
  • 2012-06-22
  • 1970-01-01
  • 2020-02-17
  • 2022-08-04
  • 2011-04-20
  • 2016-01-27
  • 1970-01-01
  • 2021-04-18
  • 1970-01-01
相关资源
最近更新 更多