Reputation: 477
How to count files in a folder and subfolder files also. folder name and file count and sub folder name and file count. Ex:
test1 : 2
test1\test11 :3
newfolder : 5
newfolder : 10
like this.
Upvotes: 0
Views: 4182
Reputation: 70923
robocopy "x:\target\folder" "x:\target\folder" /l /nocopy /is /e /nfl /njh /njs
or
pushd "x:\target\folder" && (
robocopy . . /l /nocopy /is /e /nfl /njh /njs
popd
)
This will simply call robocopy
, but instead of copying anything, we will request that nothing will be copied and only return the list of what should be processed (/nocopy /l
). We request to copy from the current folder (a previous pushd
command is used) to the current folder, including identical files in the process (/is
), processing empty subfolder (/e
, to include folders with 0 files), but only process two levels (/lev:2
the current folder and the one below), without generating a file list (/nfl
), no job header (/njh
) and no job summary (/njs
)
The result will be the same list but with the folder name and the number of files in changed columns
To keep the original output format
@echo off
setlocal enableextensions disabledelayedexpansion
pushd "x:\target\folder" && (
for /f "tokens=1,*" %%a in ('
robocopy . . /l /nocopy /is /e /nfl /njh /njs
') do echo %%~fb : %%a
popd
)
This will use a for /f
to process the previous robocopy
command, splitting the line in two tokens, the first will contain the number of files and will be stored in %%a
, and the second the rest of the line and will be stored in %%b
. For each line in the output of the inner robocopy
command, the code in the do
clause is executed: just echo to console the two tokens in reverse order.
If robocopy
can not be used (OS older than Vista), then
@echo off
setlocal enableextensions disabledelayedexpansion
for /d /r "x:\target\folder" %%a in (*) do for /f "tokens=1,5" %%b in ('
dir /a-d "%%~fa.\*" 2^> nul ^| findstr /b /c:" " ^|^| echo 0
') do if "%%c"=="" echo %%~fa : %%b
This will
for /r /d
) grab a reference and store it in %%a
replaceable parameterdir
command with the full path of the folder %%~fa
|
) to filter the list to only retrieve the lines that start with two spaces (the footer lines)dir
command failed) output a 0dir | findstr
are handled with a for /f
command. We will read the first token (the number of files in the adecuated line) and the fifth (only present in the footer line with the directories info)The problem with this approach is that the dir | findstr
is executed for each of the subfolders. This will make this slower than the robocopy
solution.
It can be faster, but more code is needed
@echo off
setlocal enableextensions disabledelayedexpansion
set "root=%cd%"
set "folder="
for %%r in ("%root%") do (
set "rootDrive=%%~dr\"
if not defined rootDrive set "rootDrive=\\"
for /f "delims=" %%a in ('
dir /s /a "%%~fr.\*" 2^>nul ^| findstr /r /c:"^ " /c:"^ .*\\."
') do for /f "tokens=1,* delims=\" %%b in ("%%~a") do if not "%%c"=="" (
set "folder=%%c"
) else if defined folder (
for /f %%d in ("%%~a") do (
setlocal enabledelayedexpansion
echo(!rootDrive!!folder! : %%d
endlocal
)
set "folder="
)
)
In this case, we will execute only one dir
command to retrieve the full list and filter with findstr
the list to only retrieve the lines with the name of the folder and the footer for each folder.
The code will iterate (for /f %%a
) over this list. When a folder line is found (it contains a backslash and can be splitted by the for /f %%b
), the folder name is saved in a variable. When the corresponding footer line is readed (it was not splitted by a backslash), the line is splitted to get the number of files (for /f %%d
) and the folder name and the number of files are echoed to console (here delayed expansion is needed to retrieve the variable contents, as they were set inside the same loop)
Note: Using a for /f
to process a large list of data generated by executing a command can be really slow (there is a bad behaviour in how the command handles memory). For this cases it is necessary to first execute the command that generates the data (dir | findstr
in this case) sending its output to a file and then use the for /f
to process the file.
@echo off
setlocal enableextensions disabledelayedexpansion
set "root=%~1"
if not defined root for %%a in (.) do set "root=%%~fa"
set "folder="
for %%t in ("%temp%\%~nx0.%random%%random%.tmp") do for %%r in ("%root%") do (
set "rootDrive=%%~dr\"
if not defined rootDrive set "rootDrive=\\"
( dir /s /a "%%~fr.\*" 2^> nul | findstr /r /c:"^ " /c:"^ .*\\." ) > "%%~ft"
for /f "usebackq delims=" %%a in ("%%~ft") do (
for /f "tokens=1,* delims=\" %%b in ("%%~a") do if not "%%c"=="" (
set "folder=%%c"
) else if defined folder (
for /f %%d in ("%%~a") do (
setlocal enabledelayedexpansion
echo(!rootDrive!!folder! : %%d
endlocal
)
set "folder="
)
)
del /q "%%~ft"
)
edited to adapt to comments: robocopy
solution changed to include total number of files
@echo off
setlocal enableextensions disabledelayedexpansion
set "total=0"
pushd "x:\target\folder" && (
for /f "tokens=1,*" %%a in ('
robocopy . . /l /nocopy /is /e /nfl /njh /njs
') do (
echo %%~fb : %%a
set /a "total+=%%a"
)
popd
)
echo Total files: %total%
Upvotes: 6