2016-02-05 88 views
1

我需要編程技術人員幫助您創建批處理腳本或PowerShell腳本,該腳本將根據平均總文件大小將一組文件從一個目錄移動到4個子目錄。排序之後,子文件夾的大小應該大致相等。根據平均文件大小將文件移動到子文件夾中

爲什麼我需要這個?

我有4臺計算機,我想通過FFMPEG進行編碼,它將有助於腳本根據總平均大小將文件夾分爲4個部分(子目錄)。

所以我們可以說有各種各樣的不同文件大小的電影文件總數達到100 GB,腳本會將電影文件分割並將它們移動到4個子文件夾中;每個文件夾大約有25 GB。這樣做可以讓4臺機器平等有效地對數據總和進行編碼。

經過所有的編碼後,我將有2個文件,XYZ(原始擴展名)和XYZ.264,一個可以比較2個文件並刪除較大文件的腳本將非常有用,並會減少人工檢查。

謝謝,我希望這是可能的。

回答

0
@ECHO Off 
SETLOCAL ENABLEDELAYEDEXPANSION 
SET "sourcedir=U:\sourcedir" 
SET "destdir=U:\destdir" 
PUSHD "%sourcedir%" 
:: number of subdirectories 
SET /a parts=4 
:: make subdirs and initialise totalsizes 
FOR /L %%a IN (1,1,%parts%) DO MD "%destdir%\sub%%a" 2>nul&SET /a $%%a=0 
:: directory of sourcefiles, sort in reverse-size order 
FOR /f "tokens=1*delims=" %%a IN (
    'dir /b /a-d /o-s * ' 
) DO (
REM find smallest subdir by size-transferred-in 
SET /a smallest=2000000000 
FOR /L %%p IN (1,1,%parts%) DO IF !$%%p! lss !smallest! SET /a smallest=!$%%p!&SET part=%%p 
REM transfer the file and count the size 
ECHO(MOVE "%%a" "%destdir%\sub!part!" 
REM divide by 100 as actual filelength possibly gt 2**31 
SET "size=%%~za" 
IF "!size:~0,-2!" equ "" (SET /a $!part!+=1) ELSE (SET /a $!part!=!size:~0,-2! + $!part!) 
) 
popd 
GOTO :EOF 

我相信這些言論應該解釋方法。其原理是記錄傳輸到每個子目錄的長度,並選擇最少填充爲文件的目的地(以反向大小順序處理)

由於批次的限制爲2^31,因此我選擇了粗略通過削減最後2位數字將文件大小除以100。對於文件< 100字節,我任意記錄爲100字節。

您需要更改sourcedirdestdir的設置以適合您的情況。

所需的MOVE命令僅爲ECHO用於測試目的。 確認命令正確後,將ECHO(MOVE更改爲MOVE以實際移動文件。附加>nul以禁止報告消息(例如,1 file moved


@ECHO OFF 
SETLOCAL ENABLEDELAYEDEXPANSION 
SET "destdir=U:\destdir" 
SET "spaces=        " 
FOR /f "delims=" %%a IN (
    'dir /b /ad "%destdir%\*"' 
) DO (
PUSHD "%destdir%\%%a" 
FOR /f "delims=" %%f IN (
    'dir /b /a-d "*.xyz" 2^>nul' 
) DO (
    IF EXIST "%%f.264" (
    FOR %%k IN ("%%f.264") DO (
    SET "sizexyz=%spaces%%%~zf" 
    SET "size264=%spaces%%%~zk" 
    IF "!sizexyz:~-15!" gtr "!size264:~-15!" (ECHO(DEL /F /Q "%%f") ELSE (ECHO(DEL /F /Q "%%f.264") 
    ) 
    ) 
) 
popd 
) 

GOTO :EOF 

此第二批掃描數據夾入%%a然後teporarily切換到detination目錄%destfile\%%a

一旦那裏,我們尋找.xyz文件,並找到每一個找到相應的.xyz.264文件。

如果存在,那麼我們找到文件的大小(%%~zk%%~zf)並將其附加到一長串空格。通過比較結果的最後15個字符作爲字符串,我們可以確定哪個更長。

爲了測試目的,所需的DEL命令僅僅是ECHO驗證命令是否正確後,將ECHO(DEL更改爲DEL以實際刪除文件。

(只有~n選擇名稱部分)如果.264文件是filename.264代替filename.xyz.264然後替換每個"%%f.264""%%~nf.264"


要手動輸入源目錄名,使用

SET /p "sourcedir=Source directory " 

要接受源目錄名作爲參數,使用

SET "sourcedir=%%~1" 

來處理所有的文件,除了.h264文件,更改

FOR /f "delims=" %%f IN (
    'dir /b /a-d "*.xyz" 2^>nul' 
) DO (

FOR /f "delims=" %%f IN (
    'dir /b /a-d "*.*" 2^>nul' 
) DO if /i "%%~xf" neq ".h264" (

其中*.*意味着「所有文件」,並額外if語句檢查擴展到文件名%%f%%~xf)是否不等於(neq.h264/i指引「不管情況( case-不敏感)「

+0

哇,這真是太神奇了,每個子目錄在我做的測試中都完美分離! – darkshaed

+0

有沒有辦法比較兩個文件具有完全相同的文件名,但擴展名不同,並自動刪除較大的文件?例如,如果我有500mb 1.mp4和200mb 1.h264腳本會刪除較大的文件? – darkshaed

+0

非常感謝您的腳本,它運行得非常漂亮 – darkshaed

1

這可能看起來像一個簡單的請求,但exact partitioning is actually a really hard problem

近似有點公平分配的最簡單方法就是對所有文件進行排序(從大到小),然後一個接一個地分配他們到ñ組(有點像如果你給了他們的卡紙牌遊戲):

# Define number of subgroups/partitions 
$n = 4 

# Create your destination folders: 
$TargetFolders = 1..$n |ForEach-Object { 
    mkdir "C:\path\to\movies\sub$_" 
} 

# Find the movie files sort by length, descending 
$Files = Get-ChildItem "C:\path\to\movies" -Recurse |Where-Object {'.mp4','.mpg','.xyz' -contains $_.Extension} |Sort-Object Length -Descending 

for($i = 0; $i -lt $Files.Count; $i++) 
{ 
    # Move files into sub folders, using module $n to "rotate" target folder 
    Move-Item $Files[$i].FullName -Destination $TargetFolders[$i % $n] 
} 

如果要包括多個文件類型,使用Where-Object過濾器代替Filter參數與Get-ChildItem

$Files = Get-ChildItem "C:\path\to\movies" -File -Recurse |Where-Object {'.mp4','.mpg','.xyz' -contains $_.Extension} |Sort-Object Length -Descending 
+0

只是一個說明,'%$ n'是零基於(對於$ n = 4,您得到0,1,2,3重複),但您的文件夾是1基於...所以你試圖把文件放入sub0,sub1,sub2和sub3,但只有其中的3個會存在。 – TheMadTechnician

+1

@TheMadTechnician通知我使用'$ i%$ n'作爲索引訪問器的值,並且由於數組索引也是*基於零的,所以無論我命名文件夾,該問題都可以解決:) –

+0

嗯,那裏很難。謝謝,你很對!對於那個很抱歉。 – TheMadTechnician

0
#!/bin/bash 

nbr_of_dirs=4 

# Go to directory if specified, otherwise execute in current directory 
if [ -n "$1" ]; then 
    cd $1 
fi 

# Create output directories and store them in an array 
for i in $(seq 1 $nbr_of_dirs); do 
    dir=dir_$i 
    mkdir $dir 
    dirs[i]=$dir 
done 

# For every non-directory, in decreasing size: 
# find out the current smallest directory and move the file there 
ls -pS | grep -v/| while read line; do 
    smallest_dir=$(du -S ${dirs[@]} | sort -n | head -1 | cut -f2) 
    mv "$line" $smallest_dir 
done 

記得在執行此操作時將腳本文件保存在不同的目錄中。腳本迭代每個文件,所以如果腳本也在目錄中,它將被移動到其中一個子目錄。

+0

在腳本中的哪裏輸入文件目錄的路徑? – darkshaed

+0

我會從文件所在的目錄運行腳本。或者,您可以在頂部添加一行,如'cd $ 1',以將您帶到指定爲第一個輸入參數的目錄。然後在那裏執行其餘的代碼。 –

+0

嗯,我無法讓它做任何事情,謝謝你的幫助 – darkshaed

相關問題