查找所有文件并复制到另一个目的地,保持文件夹结构

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

我有一个文件夹结构,其中有一堆 *.jpg 文件分散在文件夹中。

现在我想查找 CSV 文件(仅一列)或文本文件中逐行列出的一些文件,例如

one.jpg  
ten.jpg  
five.jpg

并将所有这些 *.jpg 文件复制到另一个文件夹,保持文件夹结构如下:

outputfolder\somefolder\somefolder\one.jpg

outputfolder\somefolder\ten.jpg

outputfolder\somefolder\somefolder\somefolder\five.jpg

我怎样才能做到这一点?

这是我试过的方法

@echo off 
CLS 
REM CHECK FOR ADMIN RIGHTS 
COPY /b/y NUL %WINDIR%CF2EB6-94E6-4a60-91D8-AB945AE8CF38 >NUL 2>&1 
IF ERRORLEVEL 1 GOTO:NONADMIN 
DEL %WINDIR%CF2EB6-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 

Stack Overflow 不是免费的代码编写服务,请参阅帮助主题What topics can I ask about here?

但是,我还是为这个任务写了完整的批处理代码。从此注释代码中学习,下次尝试自己编写批处理代码,并且仅询问您是否坚持在经过多次尝试后无法自己解决的问题并且在 Stack Overflow 或任何其他网站上找不到解决方案。

源文件夹和目标文件夹的路径必须在下面的批处理脚本的顶部定义。

包含要逐行复制的文件名称的文本文件必须命名为 FileNames.txt,并且必须使用下面的批处理代码存储在源基文件夹中。

@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

要了解使用的命令及其工作原理,请打开命令提示符 window,在其中执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。

  • call /? ... 解释 %~nx0
  • copy /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • md /?
  • pause /?
  • rem /?
  • set /?
  • setlocal /?

另请阅读有关 Using command redirection operators 的 Microsoft 文章以了解 2>nul 用于抑制写入 STDERR.

的错误消息

以下代码应该可以满足您的要求:

@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

它依赖于 xcopy 如果给定相对源路径,则输出到控制台的相对路径,并且它有一个开关 /L 告诉它除了列表之外不要复制任何东西没有开关会复制什么。还有一个开关 /S 定义在子目录中递归搜索源项目。

虽然有一个小问题需要解决:xcopy /S 仅在源包含通配符 *? 时遍历子目录,但如果是专用文件则不会给出了名称。这就是 * 附加到文件名的原因。因为这当然也可以匹配一些不想要的项目,所以 findstr 用于过滤掉它们。

所以基本上有一个 for /F 循环遍历文本文件 copylist.txt 中列出的项目。在这个循环中嵌套了另一个 for /F,它枚举了前面提到的 findstr-filtered xcopy /L /S 输出的输出,它一个接一个地接收外循环的项目。嵌入式 cd 命令确保位于源目录中。 xcopy 的目标只是一个现有目录,以避免出现错误消息(请记住,由于 /L,实际上没有任何内容被复制)。

内部循环 bopy 包含一个 md 创建目标目录(树)的命令,如果不存在的话(2> nul 避免错误消息,如果之前已经创建),和一个 copy 实际执行复制的命令 activity;开关 /-Y 定义为在目标位置已存在某个项目时提示用户,您可以将其更改为 /Y 以在不询问的情况下覆盖。