使用批处理脚本快速(呃)获取文件夹大小

请参阅下面的原始问题以进行一些不同的testing比较:


所以我到目前为止尝试了两种方法:

1.使用Windows命令行中“获取文件夹大小”中的代码遍历目录:

@echo off set size=0 for /r %%x in (folder\*) do set /a size+=%%~zx echo %size% Bytes 

保存一个

 'dir %folder% /s /a' 

放入一个文本文件,然后在底部读取大小

3.我现在正在尝试的最后一种方法是使用du(MS的磁盘工具工具 – https://technet.microsoft.com/en-us/sysinternals/bb896651.aspx )。


现在除了#3之外,这两种方式对于我所需要的(数以千计的文件)来说似乎太慢了。 所以问题是哪一个是最快的/应该是最快的,如果有其他快速(呃)的方式来获得大小的文件夹内容有100K +文件(有100个文件夹)


开始编辑:

下面是我做比较的非常hacky的方式(屠杀我的程序看到一些输出)
有一些小错误的一些部分,如选项3将失败,因为它试图处理一个大于32位限制的数字,我敢肯定还有一些问题,但我认为一般的时机是明显的,除非我真的搞砸了在我的逻辑上。

选项I:遍历目录,使用VB脚本读取“dir”的文本输出,并在最后查找大小+将其转换为MB(原本从其他地方得到它,我实际上失去了我得到它的地方从@ MC ND选项III:使用compact命令迭代 – 从@npocmaka选项IV:从@ user1016274 – 使用robocoby

(还有更多的答案,但这些是我已经能够纳入)

这些是我得到的结果,而且它们之间的相关性非常一致,robocopy把它们吹走了

scheme一和scheme二通常很接近,scheme二稍好一些(对于两者都是1分10秒到2分10秒,不知道差异来自哪里)第三部分 – 16-17分钟第四部分 – 10-20秒

 @echo OFF setlocal enabledelayedexpansion REM OPTION I - directory iteration REM OPTION II - iteration with findstr pipe REM OPTION III - compact :MAIN REM Initialize log filename for /f "delims=" %%a in ('echo %date:~10,4%%date:~4,2%%date:~7,2%%time:~0,2%%time:~3,2%%time:~6,2%') do @set LOGFILEPOSTFIX=%%a set LOGFILEPOSTFIX=%date:~10,4%%date:~4,2%%date:~7,2%%time:~0,2%%time:~3,2%%time:~6,2% set TIMESTAMP=%date:~10,4%_%date:~4,2%_%date:~7,2%_%time:~0,2%_%time:~3,2%_%time:~6,2% echo %TIMESTAMP% set "LOGFILE=Proj_not_in_db_%LOGFILEPOSTFIX%.log" set option=1 set TIMESTAMP=%date:~10,4%_%date:~4,2%_%date:~7,2%_%time:~0,2%_%time:~3,2%_%time:~6,2% echo %TIMESTAMP% - PART I ---- Directory Listing into file, iterate through the sizes of all files inside folder >> %LOGFILE% echo %TIMESTAMP% - PART I call :PROCESSFOLDER set TIMESTAMP=%date:~10,4%_%date:~4,2%_%date:~7,2%_%time:~0,2%_%time:~3,2%_%time:~6,2% echo %TIMESTAMP% - PART I ---- END >> %LOGFILE% echo %TIMESTAMP% - PART I - END set option=2 set TIMESTAMP=%date:~10,4%_%date:~4,2%_%date:~7,2%_%time:~0,2%_%time:~3,2%_%time:~6,2% echo %TIMESTAMP% - PART II findstr pipe ---- >> %LOGFILE% echo %TIMESTAMP% - PART II call :PROCESSFOLDER set TIMESTAMP=%date:~10,4%_%date:~4,2%_%date:~7,2%_%time:~0,2%_%time:~3,2%_%time:~6,2% echo %TIMESTAMP% - PART II ---- END>> %LOGFILE% echo %TIMESTAMP% - PART II - END set option=3 set TIMESTAMP=%date:~10,4%_%date:~4,2%_%date:~7,2%_%time:~0,2%_%time:~3,2%_%time:~6,2% echo %TIMESTAMP% - PART III compact ---- >> %LOGFILE% echo %TIMESTAMP% - PART III call :PROCESSFOLDER set TIMESTAMP=%date:~10,4%_%date:~4,2%_%date:~7,2%_%time:~0,2%_%time:~3,2%_%time:~6,2% echo %TIMESTAMP% - PART III ---- END>> %LOGFILE% echo %TIMESTAMP% - PART III - END set option=4 set TIMESTAMP=%date:~10,4%_%date:~4,2%_%date:~7,2%_%time:~0,2%_%time:~3,2%_%time:~6,2% echo %TIMESTAMP% - PART IV robocopy ---- >> %LOGFILE% echo %TIMESTAMP% - PART IV call :PROCESSFOLDER call :CLEANUP echo FINAL pause goto :EOF :PROCESSFOLDER echo C:\Windows echo Processing C:\Windows >> %LOGFILE% break > projects_in_folder.tmp for /f "tokens=1-4,* SKIP=7" %%b IN ('dir "C:\Windows" /Q /TW /AD') do ( set _folder=%%f REM Don't write the 2 lines at the end displaying summary information if NOT "%%e" EQU "bytes" ( SET _folder=!_folder:~23! echo !_folder!,%%b>> projects_in_folder.tmp ) ) set "folder_path=C:\Windows" call :COMPARE goto :EOF :COMPARE set file_name=%folder_path:\=_% break > "%file_name%.txt" if %option%==4 ( set "full_path=C:\Windows" call :GETFOLDERINFO4 set TIMESTAMP=%date:~10,4%_%date:~4,2%_%date:~7,2%_%time:~0,2%_%time:~3,2%_%time:~6,2% echo %TIMESTAMP% - PART IV ---- END>> %LOGFILE% echo %TIMESTAMP% - PART IV - END ) for /f "tokens=1,2* delims=," %%a in (projects_in_folder.tmp) do ( for /f "tokens=1,* delims=_" %%x in ("%%a") do ( set "projcode=%%x" ) set full_path=%folder_path%\%%a if %option%==1 call :GETFOLDERINFO if %option%==2 call :GETFOLDERINFO2 if %option%==3 call :GETFOLDERINFO3 echo PROJ: %%a SIZE: !totalsize! LASTMODIFIED: %%b >> %LOGFILE% ) goto :EOF :GETFOLDERINFO2 set "size=0" set target=!full_path! for /f "tokens=3,5" %%a in (' dir /a /s /w /-c "%target%" ^| findstr /b /l /c:" " ') do if "%%b"=="" set "size=%%a" echo %size% set totalsize=%size% goto :EOF :GETFOLDERINFO4 pushd "%full_path%" || goto :EOF setlocal for /f "tokens=1-10,* delims= " %%a in (' robocopy %full_path% %TEMP% /S /L /BYTES /XJ /NFL /NDL /NJH ^| find "Bytes" ') do echo %full_path%: %%c popd goto :EOF :GETFOLDERINFO set totalsize=0 dir "%full_path%" /s /a > size.txt REM Run VBScript that outputs size in MB which is saved pushd %~dp0 start /b "" cscript /nologo foldersize.vbs FOR /F "usebackq tokens=*" %%r in (`CSCRIPT "foldersize.vbs"`) DO SET totalsize=%%r echo bla > nul goto :EOF :GETFOLDERINFO3 set "last=#" set "_size=" for /f "tokens=1 delims= " %%s in ('compact /s:"%full_path%" /q ') do ( set "_size=!last!" set "last=%%s" ) set "_size=%_size: =%" set "_size=%_size: =%" set "_size=%_size:.=%" set "_size=%_size:,=%" set "_size=%_size: =%" echo folder size is : %_size% bytes set totalsize=%_size% goto :EOF :CLEANUP DEL /Q /S projects_in_folder.tmp DEL /Q /S size.txt goto :EOF 

经过一些测试和比较的表现

dir /s
compact /s
和PowerShell的GetChild-Item

我发现使用robocopy要快得多。 另外一个好处是,即使很长的路径也不会导致错误(路径中> 256个字符),例如在深度嵌套的文件夹中。
而且,如果您不想统计可以轻松包含在robocopy路口数据,请执行以下操作:

 @echo off pushd "%~1" || goto :EOF for /f "tokens=2 delims= " %%a in (' robocopy "%CD%" "%TEMP%" /S /L /BYTES /XJ /NFL /NDL /NJH /R:0 ^| find "Bytes" ') do echo %CD%: %%a popd 

如果省略/BYTES选项,您将获得格式为MB或GB的大小值。 在这种情况下,必须使用另一个循环变量来打印维度(k,m,g,t表示千,兆,千兆,泰拉)

 for /f "tokens=2-3 delims= " %%a in (' robocopy "%CD%" "%TEMP%" /S /L /XJ /NFL /NDL /NJH /R:0 ^| findstr "Bytes" ') do ( set dim=%%b set "dim=!dim:k=KB!" & set "dim=!dim:m=MB!" & set "dim=!dim:g=GB!" & set "dim=!dim:t=TB!" if !dim! EQU %%b set dim=B echo ^ %CD%: %%a !dim! ) 

%%b包含维度字母或数字值。 这是通过替换来测试以避免set /A的32位限制。

你可以尝试(本着你的第二种情况)

 @echo off setlocal enableextensions disabledelayedexpansion set "target=%~1" if not defined target set "target=%cd%" set "size=0" for /f "tokens=3,5" %%a in (' dir /a /s /w /-c "%target%" ^| findstr /b /l /c:" " ') do if "%%b"=="" set "size=%%a" echo %size% 

尝试这个:

 :foldersize @echo off pushd "%~1" setlocal set "_size=" for /f "tokens=1 delims=t" %%s in ('compact /s /q ^|find " total bytes"') do ( set "_size=%%s" ) set "_size=%_size: =%" set "_size=%_size: =%" set "_size=%_size:.=%" set "_size=%_size:,=%" set "_size=%_size: =%" echo folder size is : %_size% bytes endlocal popd 

它接受一个参数 – 文件夹。compact compact /s /q (/ q用于报告,所以不会改变将被应用)产生较少的输出,并且有机会比DIR快。

编辑:一点点优化的变种(一个是@ MC MD的 – 可能是更快)。这个想法是跳过FIND或FINDSTR使用,因为它们是外部程序,并会使脚本变慢:

 :foldersize @echo off pushd "%~1" setlocal enableDelayedExpansion set "last=#" set "_size=" for /f "tokens=1 delims= " %%s in ('compact /s /q') do ( set "_size=!last!" set "last=%%s" ) set "_size=%_size: =%" set "_size=%_size: =%" set "_size=%_size:.=%" set "_size=%_size:,=%" set "_size=%_size: =%" echo folder size is : %_size% bytes endlocal popd 

 @echo off :original script by MC ND setlocal enableextensions enableDelayedExpansion set "target=%~1" if not defined target set "target=%cd%" set "size=0" set "last=#" set "pre_last=#" rem set "pre_pre_last=#" for /f "tokens=3" %%a in (' dir /a:-d /s /w /-c "%target%" ') do ( set "pre_last=!last!" set "last=%%a" ) echo !pre_last! 

既然你愿意使用VBScript(基于你的问题下面的注释),那么你可以简单地使用FileSystemObject Folder对象的Size属性。 它报告文件夹内所有文件的总大小,包括所有子文件夹中的文件(递归)。

以下简单的JScript脚本输出当前文件夹的大小:

 var fso = new ActiveXObject("Scripting.FileSystemObject"); WScript.Echo(fso.GetFolder('.').Size); 

我选择了JScript而不是VBScript,因为在批处理脚本中嵌入JScript非常简单(尽管有一些方法可以和VBScript一样)。

下面是一个简单的混合脚本实用程序,它报告您传入的任何路径的总大小,作为第一个参数和唯一的参数。 混合脚本使调用非常方便,因为您不必指定CSCRIPT。

FolderSize.bat

 @if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment ::FolderSize.bat FolderPath :: :: Print the total size of all files within FolderPath, :: including all sub-folders, recursively. ::******** Batch Code ********* @echo off cscript //nologo //e:jscript "%~f0" %1 exit /b ********** JScript Code *******/ var fso = new ActiveXObject("Scripting.FileSystemObject"); WScript.Echo(fso.GetFolder(WScript.Arguments.Unnamed(0)).Size); 

唯一的限制是您必须有权访问文件夹内的所有文件夹(和文件?),否则会失败并显示错误消息。

我认为循环compactdir命令的每行输出是低效的,可以通过过滤中间结果来避免:

 @echo off REM dirsize.cmd 2015-05-29 pushd "%~1" || goto :EOF setlocal for /f "tokens=1-3*" %%A in ('compact /s /a /q ^| find "databytes" ^| find /v "Auflistung"') do echo %CD%: %%A %%B %%C popd 

变化:
– 如果给定路径不存在而不是扫描当前目录,则脚本将终止 – compact /a也用于包含隐藏文件和系统文件 – 将完整的输出传送到find 。 这是一个需要依赖语言环境的搜索字符串,以过滤掉摘要行。 在德语中是“databytes”,但是这也可以包含在文件夹名称中。 因此,第二个负滤波器将抑制这些。 同样,语言环境依赖(但不要求独立)。
好处是find会比具有变量赋值的shell循环更快地丢弃输出行。 调用它的代价是微不足道的。

请注意, compact /q 不会停止压缩操作。 这只会缩短产量。 在调用compress时不提供任何参数将使其仅列出而不是压缩文件/文件夹。

编辑:虽然这些点都是有效的恕我直言,看到我的其他答案更快的方式。

如果您不反对使用PowerShell,可以使用以下脚本:

 param([String]$path=".") Get-ChildItem $path | Measure-Object -property length -sum