ROBOCOPY - 将文件夹内容复制到单个文件夹

13

这是我写的一些代码 :)

@echo off
set source="R:\Contracts\"
set destination="R:\Contracts\Sites\"
ROBOCOPY %source% %destination% *.srt *.pdf *.mp4 *.jpg /COPYALL /R:0 /S
for /r %source in (*) do @copy "%destination" .

R:\Contracts\ 文件夹下有很多包含文件的文件夹。

我想将所有内容复制到 R:\Contracts\Sites\ 并将文件夹结构展平。

所有内容都成功复制,但文件夹结构也一并复制了。

谢谢。


6个回答

26

你可以用一行PowerShell代码来实现这个功能。在这个例子中,我从所有子文件夹中筛选出扩展名为.txt的所有文件,然后将它们发送到Copy-Item命令中。

结合Get-Childitem(缩写为GCI)、-recurse和-filter命令,并将结果导出到Copy-Item命令中。首先使用-WhatIf检查输出是否符合预期。

将文件复制到另一个文件夹(在执行复制命令之前,请使用-WhatIf验证输出以确保命令正确):

Get-Childitem -recurse R:\Contracts -filter *.txt | Copy-Item -Destination R:\Contracts\Sites -WhatIf

要做你所要求的多种文件类型,你可以运行多个命令,每个文件类型对应一个命令。


1
优秀的。简单易懂。 - sonjz
1
因为应该将 Move-Item 更改为 Copy-Item,所以被踩了。如果更改了,我会点赞的。 - Stefan Karlsson
修改后使用Copy-Item和原帖中的源/目标路径。 - Casey Kuball

14
没有单一的命令可以为您扁平化目录结构,您需要使用多个命令。您可以通过使用FOR /R来遍历层次结构,并配合您选择的复制/移动命令(move、copy、xcopy、robocopy)来简单地完成它。因为您的目标文件夹在源层次结构内,所以需要使用IF来防止目标成为源。
在继续之前,您应该停下来思考如果同一个文件名出现在多个源文件夹中会发生什么。您只能在目标文件夹中保留一个版本。您能保证没有重复的名称存在吗?如果不能,哪个文件应该被保留?如何构建命令来保留您想要的文件?这种复杂情况可能是为什么从未编写过一个简单的扁平化层次结构的命令。
这里是将您的ROBOCOPY命令与FOR /R解决方案集成的方法。
@echo off
set source="R:\Contracts"
set destination="R:\Contracts\Sites"

::Not sure if this is needed
::It guarantees you have a canonical path (standard form)
for %%F in (%destination%) do set destination="%%~fF"

for /r %source% %%F in (.) do if "%%~fF" neq %destination% ROBOCOPY "%%F" %destination% *.srt *.pdf *.mp4 *.jpg /COPYALL /R:0

糟糕 - 我在那行代码的末尾漏掉了一个百分号。现在已修复。它的目的是确保路径以完全合格的标准形式表示,以使后续的 IF 语句正常工作。 - dbenham
1
你好,我有一个问题。当我使用短文件名设置源和目标时,一切都正常。但是,如果我使用长文件名,例如“c:\ files \ contract open \ site \ usa \ content clean \ over load \ psjj200”,它似乎无法工作。请帮忙解决一下,谢谢。 - Arthor
那么,这个程序如何处理重复的文件名?哪个文件会被保留? - user4084811
3
“@ColeTrumbo - 重复文件处理得不好。只有在您确信没有重复文件名的情况下,才应使用此解决方案。如果您运行上述命令并存在重复文件,则最后一个被复制的文件将会覆盖之前的文件。” - dbenham
好的解决方案,但对于大型结构(许多子文件夹),它效率低下。ROBOCOPY每次都会检查目标文件夹,因此如果您有5000个子文件夹和10000个文件,您将不得不等待平均5000次的5000个文件的审核。在我的情况下,这需要几天时间... - cineS.
显示剩余3条评论

2

与之前的PowerShell选项类似,我按照以下步骤对多级子目录音乐文件夹进行了扁平化处理:

#Get all files and not the directories
$files = Get-ChildItem -Path R:\Contracts -Recurse | Where {$_.PSIsContainer -eq $false}

#Copy items from sources to new destination
foreach ($file in $files){
    Copy-Item -Path $file.FullName -Destination R:\Contracts\Sites\$($file.Name)
}

使用-Recurse开关的Get-ChildItem将获取所有子文件夹和文件的列表。使用Where函数通过检查布尔值PSIsContainer属性来剥离任何目录。如果不剥离目录,则会在其中创建没有文件的子文件夹结构。此列表存储在$files变量中。 foreach函数遍历$files变量中的文件列表,并逐个将项目存储在$file变量中。然后,Copy-Item函数使用$file.FullName中的完整路径,将文件复制到具有相同名称的目标中,该名称来自于$file.Name

1
最近我遇到了这个问题,我想要将许多文件从层次结构中移动到一个单独的文件夹中,但是它们有一样的文件名,我想要扁平化他们,但不想覆盖它们。我编写了一个脚本,将文件移动,但将旧的层次路径的名称加入到文件名中。例如: 源文件:

(保留HTML标签)

C:\files\somefiles\file.txt

C:\files\otherfiles\file.txt

目标位置为C:\ newdir \,文件被创建为

C:\newdir\somefiles-file.txt

C:\newdir\otherfiles-file.txt

这里是代码,批处理文件1浏览文件,批处理文件2重命名并移动它们(如果要保留源,则也可以复制):
@echo off
for /r %%f in (*.*pr) do @renameandmovefilespart2.bat "%%f" "%%~ff" "%%~xf"

renameandmovefilespart2.bat

@echo off
Setlocal EnableDelayedExpansion
rem set the whole file path
set origWhole=%1
set origPathOnly=%2
set extension=%3
rem here you can set where the directory to hold the flattened hierarchy is
set destDir=c:\destinationDir\
rem  set the directory to do a string replace
rem make this the starting directory, that you dont want in the newly renamed files
set startingDir=C:\starting\directory\
set nothing=
set slash=\
rem here you can set what the character to represent the directory indicator \ in the new files 
set reaplcementDirectoryCharacter=--
set quote="
rem cut out the starting part of the directory
call set newname=%%origWhole:!startingDir!=!nothing!%%
rem replace slashes with new character
call set newname=%%newname:!slash!=!reaplcementDirectoryCharacter!%%
rem remove quotes
call set newname=%%newname:!quote!=!nothing!%%
rem @echo shortened: %newname%
rem @echo source path: %origPathOnly% newPath: %startingDir%
rem @echo extension: %extension%
rem rename the files
ren %origWhole% %newname%
rem prepare to move the file, clean up the source path
call set origPathOnly=%%origPathOnly:!quote!=!nothing!%%
move "%origPathOnly%%newname%" "%destDir%"

0

有一个旧的PCMag实用程序叫做Sweep.exe,它可以在当前目录和子目录中执行相同的命令。我不会将目标设置为源目录的子目录。请将目标放在其他地方。

http://www.rarewares.org/files/case/Sweep.zip

cd c:\contracts sweep copy *.* c:\sites

这将把c:\contracts及其子目录下的所有内容复制到c:\sites。

我使用类似的命令来扁平化目录结构。

注意重复文件的处理方式。您想覆盖还是以其他方式处理它们。


0

对于熟悉 R 的人来说,将文件复制到单个文件夹可能很容易地编写脚本如下。对于大型集合和目录结构,它比 ROBOCOPY 更有效。

## R script - Flatten files in folder structure
# declare your paths
sourcepath<-C:\\Myfolder\\PicturesInStructure"
destpath<-"C:\\Myfolder\\PicturesTogether\\"
# read source filenames with path to vector variable
fileslist<-list.files(sourcepath,
                      pattern="*.jpg",    # in this example copies JPG pictures
                      full.names=TRUE,    # retrieves full path
                      recursive=TRUE,     # runs through all subdirs
                      include.dirs=FALSE) # skips dir names (no to be copied)
# here you will get a head of your list
head(fileslist)
# ordinary loop by source filenames
for (i in 1:length(fileslist)) {
  # Number of Slashes required to extract filename from the source path
  NoS<-lengths(regmatches(fileslist[i], gregexpr("/", fileslist[i])))
  # for lengthy processes it is good to know where you are with this 
  cat(i,fileslist[i],"                       \r")
  # copy one file to a destination folder (full path composed with paste0())
  file.copy(fileslist[i],paste0(destpath,unlist(strsplit(fileslist[i],"/"))[NoS+1]))
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接