【问题标题】:Copy Subdirectories, Keep the Larger File复制子目录,保留大文件
【发布时间】:2013-09-26 03:05:00
【问题描述】:

我正在尝试在 Windows 7 计算机上合并两个目录,这些目录具有一些相同的子文件夹(但不是全部)和一些相同的文件(但不是全部)。我要复制

例如,我有以下目录结构,并想组合(复制或移动)“Dir_A”和“Dir_Z”。如果文件存在于目标目录中,我想比较文件大小并保留两个文件中较大的一个。

Dir A
    Dir B
        file 1.txt
        file 2.txt
        file 3.txt
    Dir C
        file 4.txt
    Dir D
        file 5.txt
        file 6.txt
Dir_Z
    Dir Y
        file 8.txt
    Dir C
        file 4.txt
    Dir D
        file 6.txt

我很喜欢使用 cmd 文件或 powershell。先感谢您。

编辑:修改以在导演和文件名中包含空格并添加我到目前为止的内容。

这是我目前能够做到的。除非目录或文件名中有空格,否则它似乎可以工作。

@echo off
echo :: Combine two folders, Keep the larger of any given files, Delete the other

if "%1"=="" goto :NoParam
if "%2"=="" goto :NoParam
setlocal enabledelayedexpansion
set SOURCE_DIR=%1
set DEST_DIR=%2

for /R "%SOURCE_DIR%" %%S in (*) do (
echo Source: "%%S"
@echo off

for /f "delims=" %%R in ('call MakeRelative.cmd "%%S" "%SOURCE_DIR%"') do ( 
set FILE_REL="%%R"

set filename=%DEST_DIR%\%%R
For %%D in ("!filename!") do (
Set Name=%%~nxD

if exist %DEST_DIR%\%%R (
    echo File Exists
if %%~zD lss %%~zS (
    echo Destination %%~zD is smaller than Source %%~zS
    call robocopy %%~dpS %%~dpD "!Name!" /MOV
) else  del %%S && Echo File is not larger, Deleting %%S

) else call robocopy %%~dpS %%~dpD "!Name!" /MOV
)
)
)

Pause
goto :eof

:NoParam
echo.
echo Syntax: %0 [Source_DIR] [Dest_DIR]
goto :eof

我使用 MakeRelative.cmd 如下所述:http://www.dostips.com/DtCodeCmdLib.php#MakeRelative

我很抱歉这不优雅。

【问题讨论】:

  • 看看FORFILES 命令
  • cmd 只能比较小于2^31 (2147483648) 的数字。
  • 你的意思是你的脚本除了文件名或路径中有空格时可以工作吗?
  • NYCdotNet - 是的。我澄清了我的原始帖子。谢谢。
  • "path\filename""filename" 周围使用引号来处理空格。

标签: windows batch-file cmd compare


【解决方案1】:

我不是一个 PowerShell 开发人员,但这应该可以完成工作,并且希望它比批处理文件更明显。

if($args.length -ne 3) {
    "usage: PowerShell ThisScriptName.ps1 -command ""SourceDirectory"" ""DestinationDirectory""";
    Exit
}

function CopyFileIfSourceIsLarger($SourceFile, $DestinationFile) {
    $S = New-Object IO.FileInfo($SourceFile.ToString());
    $D = New-Object IO.FileInfo($DestinationFile.ToString());
    if ($S.Length -gt $D.Length ) {
        "Overwriting smaller file " + $D.FullName;
        [IO.File]::Copy($S.FullName, $D.FullName, $true);
    }
}

$SourceDir = New-Object IO.DirectoryInfo($args[1]);
$DestinationDir = New-Object IO.DirectoryInfo($args[2]);
$SourceDirectoryPath = $SourceDir.FullName;
$DestinationDirectoryPath = $DestinationDir.FullName;

"Source Path: " + $SourceDirectoryPath;
"Destination Path: " + $DestinationDirectoryPath;

$SourceItems = Get-ChildItem -recurse $SourceDir;

"Synchronizing Directory Structure..."
foreach ($dir in $SourceItems | ? { $_ -is [IO.DirectoryInfo] })  {
  $sourceRelative = $dir.fullname.Substring($SourceDirectoryPath.length + 1);
  if ([IO.Directory]::Exists([IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative)) -eq $false) {
    "Creating folder " + [IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative);
    [IO.Directory]::CreateDirectory([IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative)) | out-null;
  }
}

"Synchronizing Files..."
foreach ($file in $SourceItems | ? { $_ -is [IO.FileInfo] })  {
    $sourceRelative = $file.fullname.Substring($SourceDirectoryPath.length + 1);
    if ([IO.File]::Exists([IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative)) -eq $true) {
        CopyFileIfSourceIsLarger ([IO.Path]::Combine($SourceDirectoryPath,$sourceRelative).ToString()) ([IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative).ToString());
    } else {
        "Creating file " + [IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative);
        [IO.File]::Copy([IO.Path]::Combine($SourceDirectoryPath,$sourceRelative).ToString(),[IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative).ToString()) | out-null;
    }
}

"All done."

#Thanks to:
#"Identifying Object Types": http://powershell.com/cs/blogs/tobias/archive/2008/10/14/identifying-object-types.aspx
#"Exiting early from foreach": http://stackoverflow.com/questions/10277994/powershell-how-to-exit-from-foreach-object
#"Calling functions with multiple parameters" http://stackoverflow.com/questions/4988226/powershell-multiple-function-parameters

当脚本运行时,文件 1、2、3、5、9 和 10 被复制,而文件 6 被覆盖,因为它在目标中更小。

这是一个设置测试用例的批处理文件(加上一些额外的文件夹来测试名称中的空格)。为了安全起见,我已经注释掉了清除目录 A 和 Z 的两行,但如果您不关心删除当前目录中文件夹 A 和 Z 中的文件,则可以删除 REM 语句。

@ECHO OFF

REM Uncomment at own risk RD /S /Q A
REM Uncomment at own risk RD /S /Q Z

MD "A\B"
echo aaaaaaaabbbbbbbbcccccccc>"A\B\file 1.txt"
echo aaaaaaaabbbbbbbbcccccccc>"A\B\file 2.txt"
echo aaaaaaaabbbbbbbbcccccccc>"A\B\file 3.txt"
MD "A\C"
echo aaaaaaaabbbbbbbbcccccccc>"A\C\file 4.txt"
MD "A\D"
echo aaaaaaaabbbbbbbbcccccccc>"A\D\file 5.txt"
echo aaaaaaaabbbbbbbbcccccccc>"A\D\file 6.txt"
MD "A\FOLDER E"
echo aaaaaaaabbbbbbbbcccccccc>"A\FOLDER E\file 9.txt"
echo aaaaaaaabbbbbbbbcccccccc>"A\FOLDER E\file 10.txt"
MD "Z\Y"
echo aaaaaaaabbbbbbbbcccccccc>"Z\Y\file 8.txt"
MD "Z\C"
echo aaaaaaaabbbbbbbbccccccccdddddddd>"Z\C\file 4.txt"
MD "Z\D"
echo aaaaaaaa>"Z\D\file 6.txt"

【讨论】:

  • 谢谢@NYCdotNet 和@Joey!这似乎有效。我用你的测试脚本和我自己的测试设置验证了这一点。我现在已经在我的生产数据上运行它。当我使用相对路径作为参数而不是绝对路径时,它会打嗝。谢谢大家。
  • “打嗝”的意思是,不是将相对地址附加到当前文件夹的地址,而是将相对地址附加到位于 C:\Users\### 的“主”文件夹##\。因此,由于文件夹不存在而出错。
猜你喜欢
  • 1970-01-01
  • 2015-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-22
  • 2021-12-07
  • 1970-01-01
相关资源
最近更新 更多