查找所有文件并复制到另一个目的地,保持文件夹结构
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
以在不询问的情况下覆盖。
我有一个文件夹结构,其中有一堆 *.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
以在不询问的情况下覆盖。