简体   繁体   English

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

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

I have a folder that has 100s of subfolders and files within those subfolders that have names with leading and trailing spaces.我有一个文件夹,其中有 100 个子文件夹和文件,这些子文件夹的名称带有前导和尾随空格。 These folders and files were created using a Node JS app.这些文件夹和文件是使用 Node JS 应用程序创建的。 I need to now remove the leading and trailing spaces from the file names of the folders and files.我现在需要从文件夹和文件的文件名中删除前导和尾随空格。

I found this script which seems to be built for this purpose.我发现这个脚本似乎是为此目的而构建的。

If I use the function to create files/folders with leading spaces mentioned on the same blog, the script is able to rename those.如果我使用 function 创建具有同一博客中提到的前导空格的文件/文件夹,脚本可以重命名这些文件/文件夹。

However, it does not work with files/folders created using the node JS app.但是,它不适用于使用节点 JS 应用程序创建的文件/文件夹。 When renaming the folder/file, it fails with -重命名文件夹/文件时,失败并显示 -

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

If I run the following cmdlets for just one folder (outside the script), it fails with the same error -如果我只为一个文件夹(脚本之外)运行以下 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

Why does Rename-Item fail for files/folders created using the app whereas it works for files/folders created using PowerShell?为什么 Rename-Item 对于使用该应用程序创建的文件/文件夹失败,而它适用于使用 PowerShell 创建的文件/文件夹?

Edit: Running on Windows Server 2016 Standard.编辑:在 Windows Server 2016 Standard 上运行。 PowerShell version - 5.1.14393.3866 PowerShell 版本 - 5.1.14393.3866

Edit 2: Updated to PowerShell 7.1.4 from here and the issue still exists.编辑 2:从此处更新到 PowerShell 7.1.4,问题仍然存在。

Trailing spaces in file / directory names are problematic on Windows (unless a filename extension is also present, and the trailing spaces are only in the base file name): Windows 上文件/目录名称中的尾随空格有问题(除非文件扩展名也存在,并且尾随空格仅出现在基本文件名中):

PowerShell, .NET, cmd.exe , and File Explorer: cmd.exe和文件资源管理器:

  • can NOT create items with such names, because the given name invariably has trailing whitespace removed before it is used.无法创建具有此类名称的项目,因为给定名称在使用前总是会删除尾随空格。

  • can NOT copy, rename, or delete such items (if they were created through other means, such as Node.js - see below), for the same reason: the given name / path has trailing spaces removed, and looking for the resulting, modified name fails.不能复制、重命名或删除此类项目(如果它们是通过其他方式创建的,例如 Node.js - 见下文),原因相同:给定的名称/路径已删除尾随空格,并寻找生成的修改后的名称失败。

  • CAN enumerate such items ( Get-ChildItem , [System.IO.Directory]::EnumerateDirectories() , dir , lists of files in File Explorer).可以枚举此类项目( Get-ChildItem[System.IO.Directory]::EnumerateDirectories()dir 、文件资源管理器中的文件列表)。

While the file-system itself allows such names, it's clearly not a good idea to create them.虽然文件系统本身允许这样的名称,但创建它们显然不是一个好主意。

Node.js allows you to create them, but fortunately also allows you to target them later for renaming or deletion. Node.js 允许您创建它们,但幸运的是还允许您稍后将它们定位为重命名或删除。

Thus, the workaround is to use Node.js for renaming too ;因此,解决方法是也使用 Node.js 进行重命名 eg:例如:

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

Here's a self-contained example that uses a temporary folder to enumerate all subdirectories and rename them by removing leading and trailing whitespace from their names, if needed:这是一个独立的示例,它使用一个临时文件夹来枚举所有子目录,并在需要时通过从它们的名称中删除前导和尾随空格来重命名它们:

# 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
}

Sample output:样本 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]

Note:笔记:

  • The approach of calling the Node.js CLI, node , for every input directory isn't efficient, but for a one-time cleanup operation that probably won't matter.为每个输入目录调用 Node.js CLI node的方法效率不高,但对于一次性清理操作来说可能无关紧要。

As workaround you can use the .MoveTo() method that both DirectoryInfo and FileInfo objects have.作为解决方法,您可以使用 DirectoryInfo 和 FileInfo 对象都具有的.MoveTo()方法。

For me this works:对我来说这有效:

# 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