根据平均文件大小将文件移动到子文件夹中

时间:2016-02-05 00:08:12

标签: powershell batch-file ffmpeg

我需要您在创建批处理脚本或PowerShell脚本时编写savant的帮助,该脚本将根据平均总文件大小将一组文件从一个目录移动并划分为4个子目录。排序后,子目录在文件夹大小方面应该大致相等。

为什么我需要这个?

我想通过FFMPEG使用4台计算机进行编码,并且根据总平均大小将脚本分成4个部分(子目录)会很有帮助。

因此,假设有各种不同文件大小的电影文件总数达到100 GB,该脚本将分割电影文件并将其移动到4个子文件夹中;每个文件夹大约有25 GB。这样做将允许4台机器平等有效地编码数据总和。

在完成所有编码后,我将有2个文件,XYZ。(原始扩展名)和XYZ.264,一个可以比较2个文件并删除较大文件的脚本将非常有用,并减少了人工检查。

谢谢,我希望这是可能的。

3 个答案:

答案 0 :(得分:1)

这似乎是一个简单的请求,但是exact partitioning is actually a really hard problem

近似公平分区的最简单方法是简单地对所有文件(从最大到最小)进行排序,然后将它们逐个分发到 n 组中(有点像你是为纸牌游戏发卡:

# 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

答案 1 :(得分: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

请记住在执行此操作时将脚本文件保留在其他目录中。该脚本遍历每个文件,因此如果脚本也在目录中,它将被移动到其中一个子目录。

答案 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,然后暂时切换到排序目录%destfile\%%a

在那里,我们会查找.xyz个文件,找到每个文件,找到相应的.xyz.264文件。

如果存在,那么我们找到文件的大小(%%~zk%%~zf)并将其附加到一长串空格。通过将结果的最后15个字符作为字符串进行比较,我们可以确定哪个更长。

为了测试目的,所需的DEL命令仅为ECHO在您确认命令正确后,将ECHO(DEL更改为DEL以实际删除文件。

如果.264文件为filename.264而不是filename.xyz.264,则将{strong>每个 "%%f.264"替换为"%%~nf.264"({{1} }}仅选择名称部分。

要手动输入源目录名,请使用

~n

要接受源目录名作为参数,请使用

 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)的扩展名是否不等于({{1无论情况如何{(1}}和%%~xf指示“(案例 - nsensitive)”