【问题标题】:Does PowerShell have a clean way of validating a path to a file to be created?PowerShell 是否有一种干净的方式来验证要创建的文件的路径?
【发布时间】:2021-02-06 03:09:36
【问题描述】:

在 Python 中,有一个简单的衬线可以采用类似 C:\somefolder\somesubfolder\file.csv 的路径,如果存在 C:\somefolder\somesubfolder\ 部分,则获取它,并告诉您它是否有效。我必须考虑到用户可能会传入绝对路径、相对路径或根本没有路径,并且文件只是写入同一目录。一些潜在的用户输入:

  • ..\an_invalid_folder\something.csv
  • C:\
  • an invalid folder\something.csv
  • something.csv
  • some_absolute_path\something.csv

在 PowerShell 中,我发现这非常麻烦。我发现像 Split-Path 这样的东西有奇怪的行为 - 例如:如果你只传递 C:\ 然后使用叶子选项运行分割路径,它会告诉你 C:\ 是叶子。现在,我明白他们为什么这样做了,但这使得解决上述问题有点难看。下面是我想出的 - PowerShell 没有像 os.path 库这样更干净地处理所有这些情况的东西吗?

$ParentPath = $(Split-Path -Path $OutputFilePath -Parent)
if ($ParentPath -ne "") {
  if (-not $(Test-Path -PathType Container $ParentPath)) {
    Write-Error "The path you provided for $($OutputFilePath) is not valid." -ErrorAction Stop
  }
}

if (Test-Path $(Split-Path -Path $OutputFilePath -Leaf) -PathType Container) {
  Write-Error "You must provide a filename as part of the path. It looks like you only provided a folder in $($OutputFilePath)!" -ErrorAction Stop
}

Try { [io.file]::OpenWrite($outfile).close() }
Catch { Write-Error "It looks like you may not have permissions to $($OutputFilePath). We tried to open a file object there and the test failed." -ErrorAction Stop }

【问题讨论】:

  • 想要单线? (@(Split-Path $OutputFilePath -Parent |Where-Object {$_} |Test-Path)-eq$false).Count-eq0 :-D
  • 查看Get-Help Resolve-Path 及其返回的属性。

标签: powershell validation


【解决方案1】:
  • 毫无疑问,PowerShell 的*-Path cmdlet 有改进的余地,特别是允许指定路径(部分)不存在(目前) - 例如,参见Convert-Path 相关的GitHub proposal #2993

  • 虽然直接使用静态 .NET System.IO.Path 类的方法提供了一种解决方法,但值得注意的 - 和 unavoidable - 陷阱是 .NET 的当前目录通常不同于 PowerShell 的 ,这意味着:

    • 您通常应该始终将完整路径传递给.NET方法(对于现有路径,首先将路径传递给Convert-Path可以确保那)。在您的情况下,如果给定 相对(或仅文件名)路径,[io.file]::OpenWrite() 调用可能会失败或创建文件 elsewhere

      • 此外,.NET 对 PowerShell 特定驱动器(使用 New-PSDrive 创建)一无所知,因此基于此类驱动器的路径必须转换为 file-system-native 路径 - 再次,Convert-Path 这样做。

      • 要将 PowerShell 的当前目录作为本机文件系统路径,请使用 $PWD.ProviderPath(或者,如果当前位置可能是文件系统之外的提供程序其他的位置,例如 Windows 上的 注册表(Get-Location -PSProvider FileSystem).ProviderPath)。

    • 同样,[System.IO.Path]::GetFullPath() 专门解析相对于 .NET 的当前目录的相对路径,因此它通常不会按预期工作(除非您明确首先同步当前目录,[Environment]::CurrentDirectory = $PWD.ProviderPath)。

      • 仅限 PowerShell (Core) 7+ 您可以使用允许传入 参考目录:

        • [System.IO.Path]::GetFullPath('foo', $PWD.ProviderPath)

这里有一个比你的解决方案稍微简单,它部分依赖于底层的 .NET 异常来提供有意义的错误消息:

try { 
  $null = New-Item -ErrorAction Stop -Type File $OutputFilePath
} catch { 
  Throw "`"$OutputFilePath`" is not a valid -OutFilePath argument: " + $(
    if (Test-Path -PathType Container -LiteralPath $OutputFilePath) { 
      "Please specify a path to a *file*, not just a directory." 
    } else  {
      $_.Exception.Message
    }
  )
}

# Note: As with your approach, file $OutFilePath now exists as an empty, 
#       in a closed state.

【讨论】:

    猜你喜欢
    • 2015-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-18
    相关资源
    最近更新 更多