在下面的代码中,我需要将文件夹和子文件夹的路径和大小放入文件中。但是当循环第二次运行时,路径和大小不会打印到文件中。size.txt 仅包含第一个文件夹的路径和大小。请有人帮帮我。
@echo off
SETLOCAL EnableDelayedExpansion
SET xsummary=
SET xsize=
for /f "tokens=1,2 delims=C" %%i IN ('"dir /s /-c /a | find "Directory""') do (echo C%%j >> abcd.txt)
for /f "tokens=*" %%q IN (abcd.txt) do (
cd "%%q"
For /F "tokens=*" %%h IN ('"dir /s /-c /a | find "bytes" | find /v "free""') do Set xsummary=%%h
For /f "tokens=1,2 delims=)" %%a in ("!xsummary!") do set xsize=%%b
Set xsize=!xsize:bytes=!
Set xsize=!xsize: =!
echo.%%q >> size.txt
echo.!xsize! >> size.txt
)
答案1
问题是— 你在每个目录中都cd
创建了一个两行文件。尝试size.txt
对于...%%h在('“dir /s /-c /a %%q | 查找“字节”| 查找/v“免费””')...
并删除cd
。
顺便问一下,您是否意识到您正在获得累计总数?例如,如果您的目录结构如下所示
10万 200K 元 400K
那么你的结果会说
A 700000 \b 200000 \c 400000
这是因为第二个dir
有/s
选项。如果这是你想要的,那就没问题;我只是认为这可能是一个疏忽。
答案2
如果你能做到,可以抓住Sysinternals 杜utility 和 running du -v <directoryname>
。输出将以千字节为单位。该-v
选项表示输出所有子目录的大小。
使用您当前的脚本,问题似乎是在循环中附加文本。一个简单的解决方法是输出到命令提示符窗口,如下所示:
echo %%q
echo !xsize!
当您运行批处理文件时,其输出发送到文本文件:test.bat > size.txt
快速提示:第一部分可以简化为:
for /f "tokens=*" %%q in ('dir /a:d /s /b') do (
cd "%%q"
...
echo !xsize!
)
find
基本上,它用/a:d
选项(仅列出目录)和(使用裸格式,无标题或摘要)替换了的使用/b
。这也会摆脱临时文件。
修改后的版本可处理名称中带有感叹号的文件夹。使用 Scott 的答案。请参阅下面的评论。
请注意,这REM
意味着这是一个评论。
@echo off
REM clear the file
type NUL > size.txt
for /f "tokens=*" %%q IN ('dir /a:d /s /b') do (
echo %%q >> size.txt
REM Run :getsize, passing "%%q" including quotes as the first parameter
call :getsize "%%q" >> size.txt
)
REM go to the end of the file, i.e. exit
goto :eof
:getsize
REM %1 is the first parameter. It should already be quoted.
for /f "tokens=*" %%h IN ('"dir /s /-c /a %1 | find "bytes" | find /v "free""') do set xsummary=%%h
for /f "tokens=1,2 delims=)" %%a in ("%xsummary%") do set xsize=%%b
set xsize=%xsize:bytes=%
set xsize=%xsize: =%
echo %xsize%
goto :eof
另一种方法是使用 PowerShell:
Get-ChildItem -Recurse | ?{ $_.PSIsContainer } | %{$_ | Add-Member -MemberType NoteProperty -Name DirSize -Value 0; $_.DirSize = $(Get-ChildItem -Recurse $_.Fullname | ?{ -not $_.PSIsContainer } | Measure-Object -Sum -Property Length).Sum; $_} | Sort-Object DirSize -Descending | Select-Object -First 10 FullName,DirSize | Format-Table -AutoSize | Out-String -Width 4096 | Out-File 'sizes.txt';
为了尽可能完整,这过于复杂了 - 而且,大多数命令都有较短的别名;这只是为了更易读。如果你将某些部分分成函数/它们自己的行,它会变得更易读,也可能更短。
扩展它:
Get-ChildItem -Recurse
递归列出所有子目录和文件
?{ $_.PSIsContainer }
过滤器只保留目录(
?
是的别名Where-Object
)。$_
指的是通过管道传输到此的对象 - 因为Get-ChildItem
传递了对象列表/数组,所以它会一次处理一个对象。%{$_ | Add-Member -MemberType NoteProperty -Name DirSize -Value 0; $_.DirSize = $(Get-ChildItem -Recurse $_.Fullname | ?{ -not $_.PSIsContainer } | Measure-Object -Sum -Property Length).Sum; $_}
计算每个目录的大小(
%
是的别名Foreach-Object
,因此在每个单独的对象上运行之间的内容{ }
。每个对象都是一个目录,按照前面的部分。)扩展它:
$_ | Add-Member -MemberType NoteProperty -Name DirSize -Value 0;
分号 (
;
) 表示行/语句的结束,与管道 (|
) 相反,它不会传递输出。此特定位没有输出,它只是将属性添加DirSize
到目录对象并将其初始化为 0。这样做是为了以后更容易过滤和更整洁的输出。$_.DirSize = $(Get-ChildItem -Recurse $_.Fullname | ?{ -not $_.PSIsContainer } | Measure-Object -Sum -Property Length).Sum;
设置为该命令输出的属性。
DirSize
意味着执行括号内的内容并将其替换。Sum
$()
扩展它:
Get-ChildItem -Recurse $_.Fullname
获取当前目录对象的所有内容(
$_
,Fullname
仅表示完整路径)。-Recurse
表示也计算子目录的内容。?{ -not $_.PSIsContainer }
过滤以便只保留文件。目录的属性
Length
为 0,因此我们需要使用总和来计算其中的文件数 - 本质上就是您的批处理脚本所做的,只不过我们处理的是实际的数字、对象和属性,而不是使用 来抓取“数字”作为文本find
。Measure-Object -Sum -Property Length
计算传递给它的所有属性的总和
Length
。这将返回一个包含属性的对象Sum
,该属性在上面使用(.Sum
)
$_
本质上
echo
是将对象传递给下一部分。它现在有一个DirSize
属性。Sort-Object DirSize -Descending
降序排列
DirSize
Select-Object -First 10 FullName,DirSize
只输出前10个,且只输出名字和尺码
Format-Table -AutoSize | Out-String -Width 4096 | Out-File 'sizes.txt';
输出到
sizes.txt
。Format-Table
和Out-String
位是为了防止截断到控制台窗口宽度(通常为 80 个字符)。 考虑到 Windows 路径通常限制为 255 个字符(IIRC),4096 应该足以容纳任何 Windows 路径和目录大小的字符。 justAutoSize
意味着尽可能缩短而不截断,而不是用大量空格填充以适应 4096 个字符。
并且该命令作为一行程序运行cmd.exe
(您可以在 PowerShell 中运行上述版本):
powershell -c "Get-ChildItem -Recurse | ?{ $_.PSIsContainer } | %{$_ | Add-Member -MemberType NoteProperty -Name DirSize -Value 0; $_.DirSize = $(Get-ChildItem -Recurse $_.Fullname | ?{ -not $_.PSIsContainer } | Measure-Object -Sum -Property Length).Sum; $_} | Sort-Object DirSize -Descending | Select-Object -First 10 FullName,DirSize | Format-Table -AutoSize | Out-String -Width 4096 | Out-File 'sizes.txt';"