Find all files and copy to another destination keeping the folder structure

£可爱£侵袭症+ 提交于 2019-12-12 05:27:19

问题


I have a folder structure with a bunch of *.jpg files scattered across the folders.

Now I want to find some files listed in a CSV file (one column only) or a text file line by line like

one.jpg  
ten.jpg  
five.jpg

and copy all those *.jpg files to another folder keeping the folder structure like:

outputfolder\somefolder\somefolder\one.jpg

outputfolder\somefolder\ten.jpg

outputfolder\somefolder\somefolder\somefolder\five.jpg

How can I achieve this?

Here is what I've tried

@echo off 
CLS 
REM CHECK FOR ADMIN RIGHTS 
COPY /b/y NUL %WINDIR%\06CF2EB6-94E6-4a60-91D8-AB945AE8CF38 >NUL 2>&1 
IF ERRORLEVEL 1 GOTO:NONADMIN 
DEL %WINDIR%\06CF2EB6-94E6-4a60-91D8-AB945AE8CF38 >NUL 2>&1 
:ADMIN 
REM GOT ADMIN RIGHTS 
COLOR 
1F ECHO Please wait... 
FOR /R "%~dp0" %%I IN (.) DO 
for /f "usebackq delims=" %%a in ("%~dp0list.txt") do 
echo d |xcopy "%%I\%%a" "C:\B2B_output_files" /e /i 
COLOR 2F 
PAUSE 
GOTO:EOF 
:NONADMIN 
REM NO ADMIN RIGHTS 
COLOR 4F 
pause 
GOTO:EOF 

回答1:


Stack Overflow is not a free code writing service, see help topic What topics can I ask about here?

However, I have nevertheless written the entire batch code for this task. Learn from this commented code and next time try to write the batch code by yourself and ask only if you stick on a problem you can't solve by yourself after several trials and not finding a solution on Stack Overflow or any other website.

The paths of source and target base folder must be defined at top of the batch script below.

The text file containing the name of the files to copy line by line must be named FileNames.txt and must be stored in source base folder with using batch code below.

@echo off
setlocal EnableExtensions EnableDelayedExpansion

rem Define source and target base folders.

rem Note:

rem The paths should not contain an equal sign as then the
rem string substitutions below would not work as coded. The
rem target base folder can be even a subfolder of the source
rem base folder.

set "SourceBaseFolder=C:\Temp"
set "TargetBaseFolder=C:\Temp\OutputFolder"

rem Set source base folder as current directory. The previous
rem current directory is restored by command endlocal at end.

if not exist "%SourceBaseFolder%\*" (
    echo %~nx0: There is no folder %SourceBaseFolder%
    set "ErrorCount=1"
    goto HaltOnError
)

cd /D "%SourceBaseFolder%"

if not exist "FileNames.txt" (
    echo %~nx0: There is no file %SourceBaseFolder%\FileNames.txt
    set "ErrorCount=1"
    goto HaltOnError
)

rem For each file name in text file FileNames.txt in
rem source base folder the loops below do following:

rem 1. Search recursively for a file with current file name
rem    in entire directory tree of source base folder.

rem 2. If a file could be found, check its path. Skip the
rem    file if the path of found file contains the target
rem    folder path to avoid copying files to itself. This
rem    IF condition makes it possible that target base
rem    folder is a subfolder of source base folder.

rem 3. Create the folders of found file relative to source
rem    base path in target base folder. Then check if this
rem    was successful by verifying if the target folder
rem    really exists and copy the file on existing folder or
rem    output an error message on failure creating the folder.

set "ErrorCount=0"
for /F "usebackq delims=" %%N in ("FileNames.txt") do (
    for /R %%J in ("%%N*") do (
        set "FilePath=%%~dpJ"
        if "!FilePath:%TargetBaseFolder%=!" == "!FilePath!" (
            set "TargetPath=%TargetBaseFolder%\!FilePath:%SourceBaseFolder%\=!"
            md "!TargetPath!" 2>nul
            if exist "!TargetPath!\*" (
                echo Copying file %%~fJ
                copy /Y "%%~fJ" "!TargetPath!" >nul
            ) else (
                set /A ErrorCount+=1
                echo Failed to create directory !TargetPath!
            )
        )
    )
)

:HaltOnError
if %ErrorCount% NEQ 0 (
    echo.
    pause
)
endlocal

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • call /? ... for an explanation of %~nx0
  • copy /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • md /?
  • pause /?
  • rem /?
  • set /?
  • setlocal /?

And read also the Microsoft article about Using command redirection operators to understand 2>nul for suppressing error messages written to STDERR.




回答2:


The following code should do what you asked for:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LISTFILE=copylist.txt"
set "SOURCE=.\source"
set "DESTIN=.\destin"
for /F "usebackq eol=| delims=" %%L in ("%LISTFILE%") do (
    for /F "eol=| delims=" %%F in ('
        cd /D "%SOURCE%" ^
            ^& xcopy /L /S /I /Y ".\%%~L*" "%TEMP%" ^
            ^| findstr /I /R "^\..*\\%%~L$"
    ') do (
        2> nul md "%DESTIN%\%%F\.."
        copy /B /-Y "%SOURCE%\%%F" "%DESTIN%\%%F"
    )
)
endlocal
exit /B

It relies on the fact that xcopy outputs relative paths to the console if a relative source path is given, and that it features a switch /L that tells it not to copy anything but list what would be copied without the switch. There is also the switch /S which defines to search for the source item recursively also within subdirectories.

There is a small problem though which requires to be worked around: xcopy /S only walks through subdirectories if source contains a wildcard * or ?, but not if a dedicated file name is given. That is why * is appended to the file name. Since this could also match some unintended items of course, findstr is used to filter them out.

So basically there is a for /F loop that iterates through the items listed in the text file copylist.txt. Within this loop another for /F is nested that enumerates the output of the aforementioned findstr-filtered xcopy /L /S output, which receives the items of the outer loop one after another. The embedded cd command ensures to be in the source directory. The destination of xcopy is just an existing directory to avoid error messages (remember nothing is actually copied due to /L).

The inner loop bopy contains an md command that creates the destination directory (tree), if not existing (2> nul avoids error messages if has already been created earlier), and a copy command which actually performs the copying activity; the switch /-Y defines to prompt the user in case an item already exists at the destination location, you can change it to /Y to overwrite without asking.



来源:https://stackoverflow.com/questions/34627997/find-all-files-and-copy-to-another-destination-keeping-the-folder-structure

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!