Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Windows 使用批处理脚本获取文件夹大小的快速(er)方法_Windows_Batch File_Cmd_Du - Fatal编程技术网

Windows 使用批处理脚本获取文件夹大小的快速(er)方法

Windows 使用批处理脚本获取文件夹大小的快速(er)方法,windows,batch-file,cmd,du,Windows,Batch File,Cmd,Du,关于不同方式的一些测试比较,请参见以下原始问题: 到目前为止,我尝试了两种方法: 1.使用以下代码遍历目录: 2.保存a的输出 'dir %folder% /s /a' 输入文本文件,然后读取底部的大小 3.我现在尝试的最后一种方法是使用du(来自MS-)的磁盘实用工具 现在,除了#3之外,这两种方法对于我所需要的东西(100到数千个文件)来说似乎都太慢了。因此,问题是哪一个是最快的/应该是最快的,以及是否有任何其他快速(er)方法来获取包含100k+文件(有100s个文件夹)的文件夹

关于不同方式的一些测试比较,请参见以下原始问题:


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

1.使用以下代码遍历目录:

2.保存a的输出

'dir %folder% /s /a'  
输入文本文件,然后读取底部的大小

3.我现在尝试的最后一种方法是使用du(来自MS-)的磁盘实用工具


现在,除了#3之外,这两种方法对于我所需要的东西(100到数千个文件)来说似乎都太慢了。因此,问题是哪一个是最快的/应该是最快的,以及是否有任何其他快速(er)方法来获取包含100k+文件(有100s个文件夹)的文件夹内容的大小


开始编辑: 下面是我进行比较的非常简陋的方式(为了查看一些输出而破坏了我的程序)
有些部分有一些小错误,比如选项3会失败,因为它试图处理一个大于32位限制的数字,我确信还有一些问题,但我认为一般的时间安排是显而易见的,除非我真的弄乱了我的逻辑

选项一:遍历目录,使用VB脚本读取“dir”输出的文本,并查找结尾处的大小,然后将其转换为MB(最初从其他地方获取,但实际上丢失了获取位置) 选项二:使用findstr管道进行迭代,并直接从@MC-ND输出结果(不与MB对话) 选项三:使用compact命令从@npocmaka进行迭代 选项四:来自@user1016274-使用机器人

(还有更多的答案,但这些是我能够结合的答案)

这些是我得到的结果,它们之间的相关性非常一致,机器人技术将它们一扫而光

选项一和选项二通常很接近,选项二略好一些(两者都是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关闭
setlocal enableextensions disabledelayedexpansion
设置“目标=%~1”
如果未定义目标,则设置“目标=%cd%”
设置“大小=0”
对于/f“令牌=3,5”%%a,在('
目录/a/s/w/-c“%target%”
^|财务报告/提单/信用证:
“)如果“%%b”==”设置“大小=%%a”,则执行此操作
回显%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/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


我认为在
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
也用于包含隐藏文件和系统文件 -完整的输出通过管道传输到
查找
。这就是需要依赖于区域设置的搜索字符串来过滤摘要行的地方。在德语中是“Datenbytes”,但这也可以包含在foldername中。因此,第二个负滤波器将抑制这些。同样,语言环境相关(但不要求独立)。
优点是
find
丢弃输出行的速度比使用变量赋值的shell循环快。打电话的费用可以忽略不计

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

编辑:
尽管这些观点都是有效的,但请参阅我的另一个答案,以获得更快的方法。

经过一些测试并比较

dir/s

compact/s

和powershell
GetChild项

我发现使用
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位限制如果您不反对使用PowerShell,下面是一个可以使用的快速脚本:

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

由于您愿意使用VBScript(基于问题下方的注释),因此只需使用FileSystemObject文件夹对象大小属性即可。它报告文件夹中所有文件的总大小,包括所有子文件夹中的文件(递归)

以下简单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);
唯一的限制是您必须能够访问文件夹中的所有文件夹(和文件?),否则它将失败并显示一条错误消息。

我不认为是wind
var fso = new ActiveXObject("Scripting.FileSystemObject");
WScript.Echo(fso.GetFolder('.').Size);
@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);