使用批处理脚本快速获取文件夹大小的方法
Fast(er) way to get folder size with batch script
请在原始问题下方查看不同方法的一些测试比较:
到目前为止我尝试了两种方法:
1.Iterate 使用 Get Folder Size from Windows Command Line 中的代码通过目录:
@echo off
set size=0
for /r %%x in (folder\*) do set /a size+=%%~zx
echo %size% Bytes
2.Save
的输出
'dir %folder% /s /a'
写入一个文本文件,然后读入底部的尺寸
3.The 我现在尝试的最后一种方法是使用 du (来自 MS 的磁盘实用工具 - https://technet.microsoft.com/en-us/sysinternals/bb896651.aspx )。
现在除了#3 之外,这两种方式对于我需要的东西(成千上万个文件)来说似乎都太慢了。所以问题是其中哪一个是最快的/应该是最快的,以及是否有任何其他快速(更)的方法来获取具有 100k+ 个文件(并且有 100 个文件夹)的文件夹内容的大小
开始编辑:
下面是我进行比较的非常老套的方式(屠杀我的程序以查看一些输出)
有些部分存在一些小错误,例如选项 3 会失败,因为它试图处理大于 32 位限制的数字,而且我确信还有更多问题,但我认为一般时间安排很明显,除非我真的搞砸了按照我的逻辑。
选项 I:遍历目录,使用 VB 脚本读取 'dir' 的文本输出并查找末尾的大小 + 将其转换为 MB(最初是从某处获取的否则我实际上失去了我从哪里得到它的地方)
选项 II:迭代,使用 findstr 管道并直接输出结果(不转换为 MB)——来自@MC ND
选项 III:使用 compact 命令进行迭代——来自@npocmaka
选项 IV:来自@user1016274 - 使用 robocoby
(还有一些答案,但这些是我能够合并的)
这些是我得到的结果,它们之间的相关性非常一致,robocopy 把它们吹走了
选项 I 和选项 II 通常很接近,选项 II 稍微好一些(两者都在 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
你可以试试(本着你第二种情况的精神)
@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
它接受一个参数 - folder.The 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!
我认为遍历 compact
或 dir
命令的每一行输出是低效的,可以通过过滤中间结果来避免:
@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 "Datenbytes" ^| find /v "Auflistung"') do echo %CD%: %%A %%B %%C
popd
变化:
- 如果给定路径不存在而不是扫描当前目录,脚本将终止
- compact /a
也用于包含隐藏文件和系统文件
- 完整的输出通过管道传输到 find
。这是需要依赖于区域设置的搜索字符串的地方,以过滤掉摘要行。在德语中它是 "Datenbytes" 但这也可以包含在文件夹名称中。因此,第二个负过滤器将抑制这些。同样,取决于语言环境(但不要求独立)。
优点是 find
将比具有变量分配的 shell 循环更快地丢弃输出行。调用它的成本可以忽略不计。
请注意compact /q
不会停止压缩操作。它只会缩短输出。在 compress
的调用中不提供任何参数将使其仅列出而不是紧凑 files/folders。
编辑:
尽管这些观点都是有效的恕我直言,但请参阅我的其他答案以获得更快的方法。
经过一些测试和比较
的性能
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 表示千、兆、千兆、万亿),使用另一个循环变量:
@echo off
setlocal ENABLEDELAYEDEXPANSION
pushd "%~1" || goto :EOF
set "folder=%CD%"
if NOT "%folder: =%"=="%folder%" set folder="%folder%"
for /f "tokens=2-3 delims= " %%a in (
'robocopy %folder% %folder% /S /L /XJ /NFL /NDL /NJH /R:0 ^| findstr /I "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!
)
popd
此处的 robocopy
命令实际上并不复制任何内容(由于 '/L' 列表选项),而是打印包含文件大小总和的摘要行,然后对其进行解析。由于 robocopy
仍需要源文件夹和目标文件夹的有效路径,因此文件夹名称被使用了两次。
文件夹名称可能包含也可能不包含空格,因此最终需要用引号引起来。这是在第一行处理的。
%%b
包含维度字母或数值。这是通过替换来测试的,以避免 set /A
.
的 32 位限制
如果您不反对使用 PowerShell,可以使用以下快速脚本:
param([String]$path=".")
Get-ChildItem $path | Measure-Object -property length -sum
既然您愿意使用 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);
唯一的限制是您必须有权访问文件夹中的所有文件夹(和文件?),否则会失败并显示错误消息。
请在原始问题下方查看不同方法的一些测试比较:
到目前为止我尝试了两种方法:
1.Iterate 使用 Get Folder Size from Windows Command Line 中的代码通过目录:
@echo off
set size=0
for /r %%x in (folder\*) do set /a size+=%%~zx
echo %size% Bytes
2.Save
的输出'dir %folder% /s /a'
写入一个文本文件,然后读入底部的尺寸
3.The 我现在尝试的最后一种方法是使用 du (来自 MS 的磁盘实用工具 - https://technet.microsoft.com/en-us/sysinternals/bb896651.aspx )。
现在除了#3 之外,这两种方式对于我需要的东西(成千上万个文件)来说似乎都太慢了。所以问题是其中哪一个是最快的/应该是最快的,以及是否有任何其他快速(更)的方法来获取具有 100k+ 个文件(并且有 100 个文件夹)的文件夹内容的大小
开始编辑:
下面是我进行比较的非常老套的方式(屠杀我的程序以查看一些输出)
有些部分存在一些小错误,例如选项 3 会失败,因为它试图处理大于 32 位限制的数字,而且我确信还有更多问题,但我认为一般时间安排很明显,除非我真的搞砸了按照我的逻辑。
选项 I:遍历目录,使用 VB 脚本读取 'dir' 的文本输出并查找末尾的大小 + 将其转换为 MB(最初是从某处获取的否则我实际上失去了我从哪里得到它的地方) 选项 II:迭代,使用 findstr 管道并直接输出结果(不转换为 MB)——来自@MC ND 选项 III:使用 compact 命令进行迭代——来自@npocmaka 选项 IV:来自@user1016274 - 使用 robocoby
(还有一些答案,但这些是我能够合并的)
这些是我得到的结果,它们之间的相关性非常一致,robocopy 把它们吹走了
选项 I 和选项 II 通常很接近,选项 II 稍微好一些(两者都在 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
你可以试试(本着你第二种情况的精神)
@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
它接受一个参数 - folder.The 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!
我认为遍历 compact
或 dir
命令的每一行输出是低效的,可以通过过滤中间结果来避免:
@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 "Datenbytes" ^| find /v "Auflistung"') do echo %CD%: %%A %%B %%C
popd
变化:
- 如果给定路径不存在而不是扫描当前目录,脚本将终止
- compact /a
也用于包含隐藏文件和系统文件
- 完整的输出通过管道传输到 find
。这是需要依赖于区域设置的搜索字符串的地方,以过滤掉摘要行。在德语中它是 "Datenbytes" 但这也可以包含在文件夹名称中。因此,第二个负过滤器将抑制这些。同样,取决于语言环境(但不要求独立)。
优点是 find
将比具有变量分配的 shell 循环更快地丢弃输出行。调用它的成本可以忽略不计。
请注意compact /q
不会停止压缩操作。它只会缩短输出。在 compress
的调用中不提供任何参数将使其仅列出而不是紧凑 files/folders。
编辑: 尽管这些观点都是有效的恕我直言,但请参阅我的其他答案以获得更快的方法。
经过一些测试和比较
的性能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 表示千、兆、千兆、万亿),使用另一个循环变量:
@echo off
setlocal ENABLEDELAYEDEXPANSION
pushd "%~1" || goto :EOF
set "folder=%CD%"
if NOT "%folder: =%"=="%folder%" set folder="%folder%"
for /f "tokens=2-3 delims= " %%a in (
'robocopy %folder% %folder% /S /L /XJ /NFL /NDL /NJH /R:0 ^| findstr /I "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!
)
popd
此处的 robocopy
命令实际上并不复制任何内容(由于 '/L' 列表选项),而是打印包含文件大小总和的摘要行,然后对其进行解析。由于 robocopy
仍需要源文件夹和目标文件夹的有效路径,因此文件夹名称被使用了两次。
文件夹名称可能包含也可能不包含空格,因此最终需要用引号引起来。这是在第一行处理的。
%%b
包含维度字母或数值。这是通过替换来测试的,以避免 set /A
.
如果您不反对使用 PowerShell,可以使用以下快速脚本:
param([String]$path=".")
Get-ChildItem $path | Measure-Object -property length -sum
既然您愿意使用 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);
唯一的限制是您必须有权访问文件夹中的所有文件夹(和文件?),否则会失败并显示错误消息。