将文件夹拆分为具有特定大小的较小文件夹

时间:2017-02-24 11:42:18

标签: windows powershell

我正在尝试将文件夹分成最大大小为的文件夹,例如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上做了很多工作。

1 个答案:

答案 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
    }
}

您可以轻松跳过将每个项目分配到列表的中间步骤,并直接移动文件,但我觉得将示例拆分为两个使得它更清晰/更具可读性我们所做的试图做。

相关问题