将 50 个音乐文件从带有子目录的文件夹随机复制到另一个文件夹

将 50 个音乐文件从带有子目录的文件夹随机复制到另一个文件夹

我有一个文件夹结构,其中包含以下格式的音乐文件mp3flac 文件夹结构如下所示:

S:\Music\
     |___\ABBA
     |___\...
     |___\ZZTop

我正在尝试创建一个 Powershell 脚本来选择随机从目录(包括其子目录)中取出 50 个文件Music并将其放入另一个文件夹中。

我尝试过这个脚本,但是它不起作用。

$d = gci "S:\Music\*.mp3" | resolve-path  |  get-random -count 50
Copy-Item $d  -destination 'S:\Music\RandomFIles'
 

它抛出这个错误:Copy-Item : Cannot bind argument to parameter 'Path' because it is null.

答案1

为什么需要| Resolve-Path |?您需要将开关附加-File到 Get-ChildItem,这样您就不会同时检索 DirectoryInfo 对象和 FileInfo 对象。

.FullName然后在参数上使用该属性-Path(这是第一个需要字符串数组的位置参数)
参见复制项目

根据音乐收藏的大小,这可能需要一些时间才能完成

通过使用文件夹内的目标文件夹来递归迭代文件,您可能会遇到异常: “复制项目:无法用其自身覆盖项目 blah.mp3。” 为了避免这种情况,您需要附加-ErrorAction SilentlyContinue到 Copy-Item 命令。

以下复制 .MP3 和 .FLAC 文件:

# loop through the music folders and search for the file patterns you need to copy
$files = Get-ChildItem -Path 'S:\Music' -File -Include '*.mp3', '*.flac' -Recurse | Get-Random -Count 50
Copy-Item -Path $files.FullName -Destination 'S:\Music\RandomFiles' -Force -ErrorAction SilentlyContinue

但是,如果您只想复制 .MP3 文件,请注意该参数的-Filter工作速度比-Include但更快..

  • -Filter 仅允许一种文件名模式,如“*.mp3”
  • -Include允许使用名称模式数组,但仅当路径以 结尾时才能使用\*,或者当-Recurse还使用 switch时
# loop through the music folders and search for the single file pattern you need to copy
$files = Get-ChildItem -Path 'S:\Music' -File -Filter '*.mp3' -Recurse | Get-Random -Count 50
Copy-Item -Path $files.FullName -Destination 'S:\Music\RandomFiles' -Force -ErrorAction SilentlyContinue

在这两种情况下,请确保目标路径存在。


编辑

正如您所发现的,多次运行第一个代码块,每次运行后,总数可能会少于 50 个项目。这是因为Get-Random -Count 50可以返回目标文件夹中已有的文件,而上面的代码只是简单地复制它们。
此外,对于我来说,它本身是否不返回重复项尚不清楚Get-Random -Count 50。到目前为止,我还没有看到这种情况,但返回的 50 个项目可能并不总是唯一的。

为了解决这个问题,下面确保每个复制的文件都还未在目标文件夹中找到,并且它将始终返回 50 个没有重复的文件。

但有一个警告:
当反复运行时,如果源文件夹中没有尚未复制的文件,则可能会陷入无限循环。

$sourceFolder = 'S:\Music'
$destination  = 'S:\Music\RandomFiles'  # this folder MUST already exist 

# first create a Hashtable with file already in the destination folder (Names only)
$existing = @{}
Get-ChildItem -Path $destination  -File -Filter '*.mp3' | ForEach-Object { $existing[$_.Name] = $true }

# next loop through the music folders and search for the single file pattern you need to copy
# if the destination folder is NOT in the sourcefolder, you can leave out the Where-Object clause
$files = Get-ChildItem -Path $sourceFolder -File -Filter '*.mp3' -Recurse | Where-Object{ -not $_.DirectoryName.StartsWith($destination) }
# make sure you do not exceed the total number of files
$totalFiles = @($files).Count
$maxFiles = [math]::Min($totalFiles, 50)
# start a counted loop
for ($i = 0; $i -lt $maxFiles; $i++) {
    $rnd = Get-Random -Maximum $totalFiles                  # get a random array index from the complete $files collection
    if ($existing.ContainsKey($files[$rnd].Name)) { $i-- }  # file is already present; decrease the counter
    else {
        Write-Host "Copying file no. $($i + 1)/$maxFiles"
        $files[$rnd] | Copy-Item -Destination $destination  # copy the file
        $existing[$files[$rnd].Name] = $true                # and add its name to the Hashtable
    }
}

相关内容