2017-02-24 114 views
0

我試圖將文件夾拆分成最大大小爲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我想將它們拆分成儘可能少的文件夾。 –

回答

2

您描述的分區類型也稱爲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

我很欣賞這種努力,謝謝! –

相關問題