powershell - 复制前 PowerShell 复制项检查目标是否具有相同的文件名
问题描述
我有一个脚本
- 对文件和文件夹进行排序。
- 在检查可用空间的同时,以递归方式和有选择地将已排序的文件复制到多个位置。
- 重命名这些复制文件的扩展名。
脚本运行流畅。但是如果我运行脚本两次,复制部分会复制重复的文件,因为某些扩展名被重命名了。(问题只发生在重命名的扩展上)
我想不出比在递归和提取基本名称并检查目标中的现有文件时获取每个文件更好的方法。但是有成千上万的文件需要处理。所以它不会是有效的。
目录结构:
- 主要的
- SUB1
- 日期1
- 日期2
- 日期3
- 文件夹1
- 文件夹2
- 文件夹3
- 文件夹4
- file_1.extension
- file_2.extension
- file_3.extension
SUB2
- 日期1
- 日期2
- 日期3
- 类别_1
- 类别_2
- 类别_3
- sub_cat_1
- sub_cat_2
- sub_cat_3
- file_1.new_extension
- file_2.new_extension
- file_3.new_extension
对于每个月的每个日期,我都有它下面的每个文件和文件夹。
- 我将文件从 SUB1 复制到 SUB2
这是我的复制功能之一:
$threshold = 100
function Copy-1 {
$rmainingSpace = Get-FreeSpace
if($rmainingSpace -gt $threshold)
{
$Source = "source\path"
Copy-Item ($Source) -Destination "destination\path" -Filter "*.extension" -recurse -Verbose
Copy-Item ($Source) -Destination "some\other\destination\path" -Filter "*.another_extension" -recurse -Verbose
$rmainingSpace = Get-FreeSpace
}
else
{
Pause($rmainingSpace)
Copy-1
}
}
- 暂停功能暂停脚本,直到按 Enter。因此,如果磁盘空间用完,我可以清除空间并继续脚本的其余部分。
- 与此类似的其他复制功能很少。我使用多个复制功能,根据文件需要去哪里复制到不同的位置。
如果有人可以提供帮助,非常感谢。谢谢。
解决方案
正如Kory Gill评论的那样,我也不明白您为什么要更改文件的扩展名。如果目标文件应该已经存在,我的想法是在文件的基本名称上添加一个序列号。
事实上,如果您手动尝试复制/粘贴已存在的文件,Windows 也建议在文件中添加序列号。
为此,此功能可能很有用:
function Copy-Unique {
# Copies files to a destination. If a file with the same name already exists in the destination,
# the function will create a unique filename by appending '(x)' after the name, but before the extension.
# The 'x' is a numeric sequence value.
[CmdletBinding()]
Param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
[Alias("Path")]
[ValidateScript({Test-Path -Path $_ -PathType Container})]
[string]$SourceFolder,
[Parameter(Mandatory = $true, Position = 1)]
[string]$DestinationFolder,
[Parameter(Mandatory = $false, Position = 2)]
[string]$Filter = '*',
[switch]$Recurse
)
# create the destination path if it does not exist
if (!(Test-Path -Path $DestinationFolder -PathType Container)) {
Write-Verbose "Creating folder '$DestinationFolder'"
New-Item -Path $DestinationFolder -ItemType 'Directory' -Force | Out-Null
}
# get a list of file FullNames in this source folder
$sourceFiles = @(Get-ChildItem -Path $SourceFolder -Filter $Filter -File | Select-Object -ExpandProperty FullName)
foreach ($file in $sourceFiles) {
# split each filename into a basename and an extension variable
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($file)
$extension = [System.IO.Path]::GetExtension($file) # this includes the dot
# get an array of all filenames (names only) of the files with a similar name already present in the destination folder
$allFiles = @(Get-ChildItem $DestinationFolder -File -Filter "$baseName*$extension" | Select-Object -ExpandProperty Name)
# for PowerShell version < 3.0 use this
# $allFiles = @(Get-ChildItem $DestinationFolder -Filter "$baseName*$extension" | Where-Object { !($_.PSIsContainer) } | Select-Object -ExpandProperty Name)
# construct the new filename
$newName = $baseName + $extension
$count = 1
while ($allFiles -contains $newName) {
$newName = "{0}({1}){2}" -f $baseName, $count, $extension
$count++
}
# use Join-Path to create a FullName for the file
$newFile = Join-Path -Path $DestinationFolder -ChildPath $newName
Write-Verbose "Copying '$file' as '$newFile'"
Copy-Item -Path $file -Destination $newFile -Force
}
if ($Recurse) {
# loop though each subfolder and call this function again
Get-ChildItem -Path $SourceFolder -Directory | Select-Object -ExpandProperty Name | ForEach-Object {
$newSource = (Join-Path -Path $SourceFolder -ChildPath $_)
$newDestination = (Join-Path -Path $DestinationFolder -ChildPath $_)
Copy-Unique -SourceFolder $newSource -DestinationFolder $newDestination -Filter $Filter -Recurse
}
}
}
我还建议对您的Copy-1
功能进行一些更改以使用上述Copy-Unique
功能:
function Copy-1 {
[CmdletBinding()]
Param(
[Parameter(Mandatory = $true, Position = 0)]
[Alias("Path")]
[ValidateScript({Test-Path -Path $_ -PathType Container})]
[string]$Source,
[Parameter(Mandatory = $true, Position = 1)]
[string]$Destination,
[Parameter(Mandatory = $true, Position = 2)]
[int]$Threshold,
[string]$Filter = '*'
)
# you are not showing this function, so I have to assume it does what it needs to do
$remainingSpace = Get-FreeSpace
if($remainingSpace -gt $Threshold) {
Copy-Unique -SourceFolder $Source -DestinationFolder $Destination -Filter $Filter -Recurse -Verbose
}
else {
$answer = Read-Host -Prompt "Remaining space is now $remainingSpace. Press 'Q' to quit."
if ($answer -ne 'Q') {
# you have cleared space, and want to redo the copy action
Copy-1 -Source $Source -Destination $Destination -Filter $Filter
}
}
}
然后像这样使用它:
Copy-1 -Source 'source\path' -Destination 'destination\path' -Threshold 100 -Filter '*.extension'
Copy-1 -Source 'source\path' -Destination 'some\other\destination\path' -Threshold 100 -Filter '*.another_extension'
笔记
当然,使用相同的参数一遍又一遍地运行它,最终会得到很多副本,因为该函数不会比较文件是否相等。如果您想进行真正的文件夹同步,我建议您使用专用软件或使用 RoboCopy。使用 RoboCopy 进行目录同步的示例几乎可以在 Internet 上的任何地方找到,例如这里
推荐阅读
- python - 如何计算python中分类变量的频率
- javascript - Javascript for循环和if语句计数器变量范围
- firebase - Cloud Functions 的 Dialogflow 内联编辑器不接受异步
- python - 是否可以将mp4视频数据转换为webm?
- sql-server-2012 - 如何重新组织行?
- android - 如果每种颜色代表一个字符,如何显示一组颜色
- spring-boot - 普罗米修斯执行器的自定义路径
- android - 无法解决:firebase-iid-interop
- javascript - 使用 Ext.js 4.2 选择已选择的 Treenode(重新选择)
- shell - Shell 脚本输出 ISO8601