Get-Content 似乎使用當前作業目錄位置來決議實際路徑。但是,.Net System.Io.File Open() 方法沒有。決議 .Net 的相對路徑的以 PowerShell 為中心的方法是什么?
PS C:\src\t> type .\ReadWays.ps1
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[String]$Path
)
Write-Host "Path is $Path"
Get-Content -Path $Path | Out-Null
if ([System.IO.StreamReader]$sr = [System.IO.File]::Open($Path, [System.IO.FileMode]::Open)) { $sr.Close() }
PS C:\src\t> .\ReadWays.ps1 -Path '.\t.txt'
Path is .\t.txt
MethodInvocationException: C:\src\t\ReadWays.ps1:8
Line |
8 | if ([System.IO.StreamReader]$sr = [System.IO.File]::Open($Path, [Syst …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Exception calling "Open" with "2" argument(s): "Could not find file 'C:\Program Files\PowerShell\7\t.txt'."
PS C:\src\t> $PSVersionTable.PSVersion.ToString()
7.2.0
uj5u.com熱心網友回復:
我會親自輸入約束Path引數,System.IO.FileInfo然后您可以訪問該FullName屬性來處理相對路徑:
param(
[ValidateScript({
if(Test-Path $_ -PathType Leaf)
{
return $true
}
throw 'Invalid File Path'
})]
[System.IO.FileInfo]$Path
)
$reader = [System.IO.StreamReader]::new(
[System.IO.File]::Open(
$Path.FullName, [System.IO.FileMode]::Open
)
)
$reader.BaseStream
$reader.Close()
PS /> ./script.ps1 ./test.txt
Handle : 244
CanRead : True
CanWrite : True
SafeFileHandle : Microsoft.Win32.SafeHandles.SafeFileHandle
Name : /home/user/Documents/test.txt
IsAsync : False
Length : 381
Position : 0
CanSeek : True
CanTimeout : False
ReadTimeout :
WriteTimeout :
以上在 Linux 上對我來說效果很好,但是在 Windows 上似乎表現不同,感謝OP指出這一點。透視一下:
- 在 Linux 上
PS /home/user/Documents> ([System.IO.FileInfo]'./test.txt').FullName
/home/user/Documents/test.txt
- 在 Windows 上
PS C:\Users\User\Documents> ([System.IO.FileInfo]'.\test.txt').FullName
C:\Users\User\test.txt
顯然,[System.IO.FileInfo]無法按照我的預期處理相對路徑,因此我更新了適用于 Windows 和 Linux 的代碼:
param(
[ValidateScript({
if(Test-Path $_ -PathType Leaf)
{
return $true
}
throw 'Invalid File Path'
})]
[string]$Path
)
if(-not(Split-Path $Path -IsAbsolute))
{
[string]$Path = Resolve-Path $Path
}
$reader = [System.IO.StreamReader]::new(
[System.IO.File]::Open(
$Path, [System.IO.FileMode]::Open
)
)
$reader.BaseStream
$reader.Close()
上次編輯
以下應該能夠處理:
- UNC 路徑
- 在 Windows 和 Linux 上作業
- 高效
- 處理相對路徑
從$Path有效的基數開始ValidateScript attribute,我們只需要確定我們正在處理的路徑是 UNC、Relative 還是 Absolute。
UNC 路徑必須始終是完全限定的。它們可以包含相對目錄段(. 和 ..),但它們必須是完全限定路徑的一部分。您只能通過將 UNC 路徑映射到驅動器號來使用相對路徑。
We can assume a UNC path must always start with \\, so this condition should suffice to determine if $Path will be manipulated or not:
if(-not $Path.StartsWith('\\'))
Lastly, in the begin block, updating the environment's current directory each time our script or function runs with:
[Environment]::CurrentDirectory = $pwd.ProviderPath
By doing so, ([System.IO.FileInfo]$Path).FullName should give us the absolute path of our parameter, be it UNC, Relative or Absolute.
param(
[ValidateScript({
if(Test-Path $_ -PathType Leaf) {
return $true
}
throw 'Invalid File Path'
})] [string]$Path
)
begin
{
[Environment]::CurrentDirectory = $pwd.ProviderPath
}
process
{
if(-not $Path.StartsWith('\\'))
{
$Path = ([System.IO.FileInfo]$Path).FullName
}
try
{
$reader = [System.IO.StreamReader]::new(
[System.IO.File]::Open(
$Path, [System.IO.FileMode]::Open
)
)
$reader.BaseStream
}
catch
{
$_.Exception.Message
}
finally
{
$reader.Close()
$reader.Dispose()
}
}
uj5u.com熱心網友回復:
您可以添加一個測驗來查看路徑是否是相對的,如果是,則將其轉換為絕對路徑,例如:
if (![System.IO.Path]::IsPathRooted($Path) -or $Path -match '^\\[^\\] ') {
$path = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($pwd, $Path))
}
我還添加了$Path -match '^\\[^\\] '以反斜杠開頭的相對路徑,例如\ReadWays.ps1表示路徑從根目錄開始。以兩個反斜杠開頭的 UNC 路徑被視為絕對路徑。
uj5u.com熱心網友回復:
這是一個常見的問題。不知何故.net 和powershell 不同意當前目錄。
[System.IO.File]::Open("$pwd\$Path", [System.IO.FileMode]::Open)
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/376429.html
標籤:电源外壳
