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

和自甴很熟 提交于 2019-12-07 21:55:11

问题


To open and read files in powershell I use one of two methods:

Get-Content $path

or

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

While reading a log file that is in use by another process Get-Content doesn't seem to have any issues with it. Then again the powershell cmdlet is slow and uses more memory compared to .NET method. When I try to use .NET method however, I get the following error:

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

Q1: Why can't .net method access the file whilst powershell cmdlet can?

Q2: And how could I read the file with .net method? Since Get-Content is too slow for log files around 80 MB. I usually read just the last line with:

$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

Any help greatly appreciated !

PS! I'm using powershell 2.0 and can't kill the process that is using the file. Also I do not have write access to the file, just read.


回答1:


PetSerAl, as usual, has provided a terse comment that provides an effective solution and implies an explanation:

To prevent the "The process cannot access the file 'XYZ' because it is being used by another process." error, you must open the file with sharing mode FileShare.ReadWrite, so that other processes that want to write to the file aren't denied access.

This is what Get-Content (invariably) does behind the scenes, which explains why the problem doesn't surface when you use it.

By contrast, [System.IO.File]::OpenRead() defaults to sharing mode FileShare.Read, meaning that other processes can read from, but not write to the same file.

Therefore, use [System.IO.File]::Open() instead, which allows you to specify the sharing mode explicitly:

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

Note that I've omitted the System. component from the type names above; this component is always optional in PowerShell.




回答2:


If you could move to more later version of PowerShell (at least v3.0), then Get-Content -Tail is a good option. We use it widely and performance is good for our scenarios.

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".



来源:https://stackoverflow.com/questions/51618294/file-in-use-with-net-method-but-not-with-powershell-cmdlet

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!