繁体   English   中英

重命名项目失败并显示“无法重命名,因为‘C:\Folder\Example App Folder’中的项目不存在”

[英]Rename-Item fails with 'Cannot rename because item at 'C:\Folder\ Example App Folder ' does not exist

我有一个文件夹,其中有 100 个子文件夹和文件,这些子文件夹的名称带有前导和尾随空格。 这些文件夹和文件是使用 Node JS 应用程序创建的。 我现在需要从文件夹和文件的文件名中删除前导和尾随空格。

我发现这个脚本似乎是为此目的而构建的。

如果我使用 function 创建具有同一博客中提到的前导空格的文件/文件夹,脚本可以重命名这些文件/文件夹。

但是,它不适用于使用节点 JS 应用程序创建的文件/文件夹。 重命名文件夹/文件时,失败并显示 -

Rename-Item : Cannot rename because item at 'C:\Folder\ Example App Folder ' does not exist.
At C:\renamefileswithspaces.ps1:25 char:13
+             Rename-Item -LiteralPath $_.fullname -NewName (“{0}{1}{2} ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
    + FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand

如果我只为一个文件夹(脚本之外)运行以下 cmdlet,它会失败并出现相同的错误 -

$f = Get-ChildItem -Path 'C:\Folder' -Filter "*Example*"

Rename-Item -LiteralPath $f.FullName -NewName $f.Name.Trim()

Rename-Item : Cannot rename because item at 'C:\Folder\ Example App Folder ' does not exist.
At line:1 char:1
+ Rename-Item -LiteralPath $f.FullName -NewName $f.Name.Trim()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
    + FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand

为什么 Rename-Item 对于使用该应用程序创建的文件/文件夹失败,而它适用于使用 PowerShell 创建的文件/文件夹?

编辑:在 Windows Server 2016 Standard 上运行。 PowerShell 版本 - 5.1.14393.3866

编辑 2:从此处更新到 PowerShell 7.1.4,问题仍然存在。

Windows 上文件/目录名称中的尾随空格有问题(除非文件扩展名也存在,并且尾随空格仅出现在基本文件名中):

cmd.exe和文件资源管理器:

  • 无法创建具有此类名称的项目,因为给定名称在使用前总是会删除尾随空格。

  • 不能复制、重命名或删除此类项目(如果它们是通过其他方式创建的,例如 Node.js - 见下文),原因相同:给定的名称/路径已删除尾随空格,并寻找生成的修改后的名称失败。

  • 可以枚举此类项目( Get-ChildItem[System.IO.Directory]::EnumerateDirectories()dir 、文件资源管理器中的文件列表)。

虽然文件系统本身允许这样的名称,但创建它们显然不是一个好主意。

Node.js 允许您创建它们,但幸运的是还允许您稍后将它们定位为重命名或删除。

因此,解决方法是也使用 Node.js 进行重命名 例如:

node -e "fs.renameSync(' Example App directory ', 'Example App directory')"

这是一个独立的示例,它使用一个临时文件夹来枚举所有子目录,并在需要时通过从它们的名称中删除前导和尾随空格来重命名它们:

# Switch to a temporary directory.
Push-Location -ea Stop ($tmpDir = (New-Item -Type Directory -Force (Join-Path $env:TEMP/ $PID)).FullName)

try {

  # Create a test directory whose name has trailing (and leading) spaces.
  # Note: 
  #   * You cannot do this with PowerShell / cmd.exe commands.
  #   * To delete or rename such a directory, use Node.js too:
  #       node -e "fs.rmdirSync(' Example App directory ')"
  #       node -e "fs.renameSync(' Example App directory ', 'Example App directory')"
  node -e "fs.mkdirSync(' Example App directory ')"
  if ($LASTEXITCODE) { throw }

  # Create another directory, but without leading or trailing whitespace.
  $null = New-Item -Type Directory 'Example without surrounding spaces'

  # Enumerate all directories and rename them, if needed, 
  # by trimming leading and trailing whitespace.
  # Note: The Get-ChildItem call is enclosed in (...) to guard against renamed directorys
  #       re-entering the enumeration.
  (Get-ChildItem -LiteralPath . -Directory -Filter *) | ForEach-Object {
    # Determine the full path with the name part trimmed.
    $trimmedPath = Join-Path (Split-Path -LiteralPath $_.FullName) ($_.BaseName.Trim() + $_.Extension.Trim())
    if ($trimmedPath -ne $_.FullName) { # Trimming is needed.
      Write-Verbose -vb "Renaming '$($_.FullName)' to '$($trimmedPath)'..."
      # Perform the renaming via Node.js
      node -e ("fs.renameSync('{0}', '{1}')" -f ($_.FullName -replace "[\\']", '\$0'), ($trimmedPath -replace "[\\']", '\$0'))
      if ($LASTEXITCODE) { Write-Error "Renaming '$($_.FullName)' to '$($trimmedPath)' failed with exit code $LASTEXITCODE." }
    }
    else { # Trimming not needed.
      Write-Verbose -vb "Name has no leading or trailing spaces: '$($_.FullName)'"
    }
  }

  Write-Verbose -vb "Names after:"
  (Get-ChildItem).Name.ForEach({"[$_]"})

}
finally {
  # Clean up.
  Pop-Location; Remove-Item $tmpDir -Recurse
}

样本 output:

VERBOSE: Renaming 'C:\Users\jdoe\AppData\Local\Temp\3712\ Example App directory ' to 'C:\Users\jdoe\AppData\Local\Temp\3712\Example App directory'...
VERBOSE: Name has no leading or trailing spaces: 'C:\Users\jdoe\AppData\Local\Temp\3712\Example without surrounding spaces'
VERBOSE: Names after:
[Example App directory]
[Example without surrounding spaces]

笔记:

  • 为每个输入目录调用 Node.js CLI node的方法效率不高,但对于一次性清理操作来说可能无关紧要。

作为解决方法,您可以使用 DirectoryInfo 和 FileInfo 对象都具有的.MoveTo()方法。

对我来说这有效:

# get both files and directories
Get-ChildItem -Path 'C:\Folder' -Recurse | 
Where-Object { $_.BaseName -ne $_.BaseName.Trim() } |
ForEach-Object {
    # the DirectoryName property does not exist on DirectoryInfo objects..
    $path    = [System.IO.Path]::GetDirectoryName($_.FullName)  
    $trimmed = Join-Path -Path $path -ChildPath ('{0}{1}' -f $_.BaseName.Trim(), $_.Extension.Trim())
    $_.MoveTo($trimmed)
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM