我正在尝试将文件夹分成最大大小为的文件夹,例如8 GB。
开始文件夹:
Folder 1
2KB file
2GB file
7GB file
Folder 2
1GB file
5.6GB file
Folder 3
8GB file
我想变成:
Folder A (~7.6GB)
Folder 1
2KB file
2GB file
Folder 2
5.6GB file
Folder B (8GB)
Folder 1
7GB file
Folder 2
1GB file
Folder C (8GB)
Folder 3
8GB file
目标是您可以组合文件夹并获取原始文件夹的结构。
对PowerShell来说,甚至可以这样吗?我已经看到了一些使用bash和dirsplit的解决方案,但我真的很想将它保留在PowerShell中,除非有一个简单而干净的解决方案和一些现有的软件。
我忘了添加文件夹可能不仅包含文件,有时也包含文件夹。是否有一种解决方案可以在一定程度上递归地执行此操作?
感觉我错过了一些东西,考虑到我在powershell上做了很多工作。
答案 0 :(得分:2)
您描述的分区类型也称为bin packing problem。
一个相当快速的解决方案被称为 first-fit algorithm - 想象一个有限大小的无限行的箱子,并简单地将每个物品打包到下一个有空间的箱子里。这可以通过首先打包最大项目(通过预先对项目进行排序)进一步优化。
下面是一个有点冗长的实现:
# Define the root path (the one that contains Folder1, Folder2 etc)
$RootPath = 'C:\data'
# Define the target path (where we'll create the new structure)
$TargetPath = 'C:\packed'
# Collect the file information, order by descending size (largest first)
$Files = Get-ChildItem $RootPath -File -Recurse |Sort-Object Length -Descending
# Define max bin size as the size of the largest file
$Max = $Files[0].Length # puth 8GB here instead (fiels larger than 8GB will end up in a lone bin)
# Create a list of lists to group our files by
$Bins = [System.Collections.Generic.List[System.Collections.Generic.List[System.IO.FileInfo]]]::new()
:FileIteration
foreach($File in $Files){
# Walk through existing bins to find one that has room
for($i = 0; $i -lt $Bins.Count; $i++){
if(($Bins[$i]|Measure Length -Sum).Sum -le ($Max - $File.Length)){
# Add file to bin, continue the outer loop
$Bins[$i].Add($File)
continue FileIteration
}
}
# No existing bins with capacity found, create a new one and add the file
$NewBin = [System.Collections.Generic.List[System.IO.FileInfo]]::new()
$NewBin.Add($File)
$Bins.Add($NewBin)
}
# Now go through the bins and move the files to the new directory
foreach($Bin in $Bins){
# Create a new randomly named folder for the files in the bin
$Directory = New-Item $TargetPath -Name $([System.IO.Path]::GetRandomFileName()) -ItemType Directory
foreach($File in $Bin){
# Recreate the parent folder inside the new folder if it doesn't already exist
$ParentName = $File.Directory.Name
$ParentPath = Join-Path $Directory.FullName -ChildPath $ParentName
if(-not(Test-Path $ParentPath)){
$ParentDirectory = New-Item $ParentPath -ItemType Directory
}
# Move file into new directory structure
Move-Item $File.FullName -Destination $ParentPath
}
}
您可以轻松跳过将每个项目分配到列表的中间步骤,并直接移动文件,但我觉得将示例拆分为两个使得它更清晰/更具可读性我们所做的试图做。