简体   繁体   中英

batch file to count all files in a folder and subfolder files and write output file in folder name using batch file

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.

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 each folder under the start directory ( for /r /d ) grab a reference and store it in %%a replaceable parameter
  • Run a dir command with the full path of the folder %%~fa
  • Use a pipe ( | ) to filter the list to only retrieve the lines that start with two spaces (the footer lines)
  • If no lines are found (that is, the dir command failed) output a 0
  • The lines generated by the dir | findstr dir | 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)
  • If the fifth element is empty, this line has information about the files, not the folders, so, echo the folder path and the files inside it
  • At the end, restore the previous active directory

The problem with this approach is that the dir | findstr 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%

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM