[英]Find all files and copy to another destination keeping the folder structure
I have a folder structure with a bunch of *.jpg
files scattered across the folders. 我有一个文件夹结构,其中有一堆*.jpg
文件分散在文件夹中。
Now I want to find some files listed in a CSV file (one column only) or a text file line by line like 现在,我想逐行查找CSV文件(仅一列)或文本文件中列出的某些文件,例如
one.jpg
ten.jpg
five.jpg
and copy all those *.jpg
files to another folder keeping the folder structure like: 并将所有这些*.jpg
文件复制到另一个文件夹,并保持以下文件夹结构:
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
Stack Overflow is not a free code writing service, see help topic What topics can I ask about here? Stack Overflow不是免费的代码编写服务,请参阅帮助主题。在这里,我可以问哪些主题?
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. 从此注释代码中学习,下次尝试自己编写批处理代码,仅询问是否遇到无法在Stack Overflow或任何其他网站上找到解决方案后自行解决的问题。
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. 包含要逐行复制的文件名的文本文件必须命名为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
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
...用于%~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 . 并阅读有关使用命令重定向运算符的Microsoft文章,以了解2>nul
抑制写入STDERR的错误消息。
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. 它依赖于以下事实:如果给出了相对源路径,则xcopy
将向控制台输出相对路径,并且它具有一个开关/L
,它告诉它不复制任何内容,而是列出不使用该开关将被复制的内容。 There is also the switch /S
which defines to search for the source item recursively also within subdirectories. 还有/S
开关,它定义为也在子目录内递归搜索源项目。
There is a small problem though which requires to be worked around: xcopy /S
only walks through subdirectories if source contains a wildcard *
or ?
尽管有一个小问题需要解决: xcopy /S
仅在源包含通配符*
或?
遍历子目录?
, 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. 由于这当然也可以匹配某些意外项目,因此使用findstr
过滤掉它们。
So basically there is a for /F
loop that iterates through the items listed in the text file copylist.txt
. 因此,基本上有一个for /F
循环可循环访问文本文件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. 在此循环中for /F
嵌套了另一个for /F
,该枚举枚举上述findstr
过滤的xcopy /L /S
输出的输出,该输出一个接一个地接收外循环的项。 The embedded cd
command ensures to be in the source directory. Embedded cd
命令确保位于源目录中。 The destination of xcopy
is just an existing directory to avoid error messages (remember nothing is actually copied due to /L
). xcopy
的目标只是一个现有目录,以避免出现错误消息(请记住,由于/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; 内部循环bopy包含一个创建目标目录(树)的md
命令(如果尚不存在)( 2> nul
避免了先前已创建的错误消息),以及一个实际执行复制活动的copy
命令。 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. 开关/-Y
定义了在目标位置已经存在某个项目的情况下提示用户的情况,您可以将其更改为/Y
以覆盖而无需询问。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.