将文件夹拆分成一定大小的文件夹

问题描述:

我试图将文件夹拆分成最大大小为8GB的文件夹。将文件夹拆分成一定大小的文件夹

启动文件夹:

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工作过很多。

+2

我不认为你错过了任何东西。这是这些似乎微不足道的问题之一,但实际上很难找到最佳的解决方案。你是否试图将数据放入一组有限的文件夹中(即将它们分成3个文件夹)或有限大小(每个文件夹中最多8GB)? –

+0

以最大的文件(效率)开始的algorythm会得到相同的结果,但顺序不同。 – LotPings

+0

@ MathiasR.Jessen我想将它们拆分成尽可能少的文件夹。 –

您描述的分区类型也称为bin packing problem

一个相当快地解决了这个被称为第一配合算法 - 想象有限的大小的二进制位的无限线,并且简单地把每项到具有余地它下一箱。这可以通过首先将最大的物品(通过预先分拣物品)进一步优化。

下面是一个有点冗长的实现:

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

你可以平凡跳过分配每个项目列表的中间步骤,而直接进入到移动的文件,但我觉得分裂例如引入两个使得它更清晰/更具可读性我们正在尝试做的事情。

+0

击败我!非常好':-)' – gvee

+0

我很欣赏这种努力,谢谢! –