重命名项目失败,并显示"无法重命名,因为"C:\文件夹\示例应用程序文件夹"中的项目不存在



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

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

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

但是,它不适用于使用node 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

为什么重命名项目失败的文件/文件夹创建使用应用程序,而它的工作为使用PowerShell创建的文件/文件夹?

编辑:运行在Windows Server 2016标准。PowerShell版本- 5.1.14393.3866

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

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

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

  • 不能创建具有这样名称的项,因为给定的名称在使用之前总是带有尾随空格

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

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

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

Node.js允许您创建它们,但幸运的是,也允许您在以后重命名或删除它们。

因此,的解决方法是使用Node.js来重命名too;例如:
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
}

样本输出:

VERBOSE: Renaming 'C:UsersjdoeAppDataLocalTemp3712 Example App directory ' to 'C:UsersjdoeAppDataLocalTemp3712Example App directory'...
VERBOSE: Name has no leading or trailing spaces: 'C:UsersjdoeAppDataLocalTemp3712Example without surrounding spaces'
VERBOSE: Names after:
[Example App directory]
[Example without surrounding spaces]

注意:

  • 对于每个输入目录调用Node.js命令行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)
}

最新更新