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

Lau*_*ebs 5 windows powershell

我正在尝试将一个文件夹划分为最大大小为 8 GB 的文件夹。

起始文件夹:

 Folder 1
  2KB file
  2GB file
  7GB file
 Folder 2
  1GB file
  5.6GB file
 Folder 3
  8GB file
Run Code Online (Sandbox Code Playgroud)

我想把它变成:

  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
Run Code Online (Sandbox Code Playgroud)

目标是您可以组合文件夹并获取原始文件夹的结构。

使用 powershell 可以实现这样的功能吗?我已经看到了一些使用 bash 和 dirsplit 的解决方案,但我真的很想将其保留在 powershell 中,除非有一些现有软件的简单干净的解决方案。

我忘记补充一点,文件夹可能不仅包含文件,有时还包含文件夹。有没有一种解决方案可以在一定程度上递归地执行此操作?

考虑到我没有经常使用 powershell,感觉好像我错过了一些东西。

Mat*_*sen 6

您描述的分区类型也称为装箱问题

对此的一个相当快的解决方案被称为首次适应算法- 想象无限行有限大小的箱子,然后简单地将每个项目打包到下一个有空间的箱子中。这可以通过首先包装最大的物品(通过预先对物品进行排序)来进一步优化。

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

# 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
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以轻松地跳过将每个项目分配给列表的中间步骤,并直接移动文件,但我觉得将示例分成两部分可以使我们想要做的事情更清晰/更易读。