【问题标题】:Copy items from Source to Destination if they don't already exist如果项目不存在,则将项目从源复制到目标
【发布时间】:2014-09-18 15:01:44
【问题描述】:

我有一个非常基本的 powershell 复制脚本,可以将项目从源文件夹复制到目标文件夹。但是,这移动了太多数据,我想检查文件名是否已经存在,以便可以忽略该文件。我不需要像验证创建日期/校验和/等那样复杂。

目前是这样的:

Copy-Item source destination -recurse
Copy-Item source2 destination2 -recurse

我想我需要添加 Test-Path cmdlet,但我不确定如何实现它。

【问题讨论】:

    标签: powershell


    【解决方案1】:

    为此,您可以随时从PowerShell 致电ROBOCOPY

    使用 /xc(排除更改)/xn(排除较新)和 /xo(排除较旧)标志:

    robocopy /xc /xn /xo source destination 
    

    这只会复制那些不在目标文件夹中的文件。

    更多选项请输入robocopy /?

    【讨论】:

    • 我知道这已经 7 岁了,但是 robocopy 可能会跳过文件的一些原因是什么?我正在开展一个移动 16.5TB 数据的项目,并且在杂项位置有大约 7.5GB 的数据似乎无缘无故地被跳过。这些文件未使用,并且文件属性与同一目录中的其他文件相同。这发生在初始运行时,因此文件在目标位置尚不存在。在这个问题上摸不着头脑......
    • 我正在使用 Beyond Compare Ver。 4 来执行同步,但它比 RoboCopy 慢得多,因为我不能多线程。
    【解决方案2】:
    $exclude = Get-ChildItem -recurse $dest
    Copy-Item -Recurse $file $dest -Verbose -Exclude $exclude
    

    【讨论】:

    • 最好在代码中包含一些上下文/解释,因为这会使答案对 OP 和未来的读者更有用。
    • 通常我会同意,但这里的代码和变量名称非常简单明了。
    【解决方案3】:

    虽然我同意 Robocopy 是解决此类问题的最佳工具,但我完全愿意为客户提供他们所要求的东西,这是一个有趣的 PowerShell 练习。

    这个脚本应该按照您的要求做:仅当目标中不存在文件时,才将文件从源复制到目标,并且需要最少的装饰。由于您在示例中使用了 -recurse 选项,因此与仅测试目标文件夹中的文件名相比,这需要更多的编码。

    $Source = "C:\SourceFolder"
    $Destination = "C:\DestinationFolder"
    
    Get-ChildItem $Source -Recurse | ForEach {
        $ModifiedDestination = $($_.FullName).Replace("$Source","$Destination")
        If ((Test-Path $ModifiedDestination) -eq $False) {
            Copy-Item $_.FullName $ModifiedDestination
            }
        }
    

    【讨论】:

    • 谢谢,但这对我不起作用。我的具体情况是,在目标文件夹中有一个已经存在子项目的文件夹,并且该脚本没有将其他文件复制到该文件夹​​中。换句话说,源和目标都有“文件夹/其他文件夹”。目标文件只有一个子项,但同一文件夹中的源文件从未被复制进来。
    【解决方案4】:

    以 Wai Ha Lee 的帖子为基础,下面是一个对我有用的示例:

    $Source = "<your path here>"
    $Dest = "<your path here>"
    $Exclude = Get-ChildItem -recurse $Dest
    
    Get-ChildItem $Source -Recurse -Filter "*.pdf" | Copy-Item -Destination $Dest -Verbose -Exclude $Exclude
    

    这会构建一个要排除的列表,然后将源目录和子目录中的任何 pdf 复制到目标单个文件夹中...排除现有文件。同样,这是我需要的一个示例,但与您的类似。应该很容易调整到您的内心满足感。

    【讨论】:

      【解决方案5】:

      函数Copy-IfNotPresent 一次只接受一个文件,但很容易循环查找要复制的所有文件。这是一个例子:

      gci c:\temp\1\*.* -Recurse -File | % { Copy-IfNotPresent -FilePath $_ -Destination "C:\temp\2\$(Resolve-Path $_ -relative)" -Verbose }
      

      这是函数。如有必要,它将生成文件夹树。这是要点链接:https://gist.github.com/pollusb/cd47b4afeda8edbf8943a8808c880eb8

      Function Copy-IfNotPresent {
      <#
          Copy file only if not present at destination.
          This is a one file at a time call. It's not meant to replace complex call like ROBOCOPY.
          Destination can be a file or folder. If it's a folder, you can use -Container to force Folder creation when not exists
      #>
      [CmdletBinding()]
      Param (
          [Parameter(Mandatory)]
          $FilePath,
      
          [Parameter(Mandatory)]
          [string]$Destination,
      
          [switch]$Container,
      
          [switch]$WhatIf
      )
      #region validations
      if ($FilePath -isnot [System.IO.FileInfo]){
          $File = Get-ChildItem $FilePath -File
      } else {
          $File = $FilePath
      }
      
      if (!$File.Count){
          Write-Warning "$FilePath no file found."
          return
      } elseif ($File.Count -gt 1) {
          Write-Warning "$FilePath must resolve to one file only."
          return
      }
      #endregion
      
      # Destination is a folder
      if ($Container -or (Test-Path -Path $Destination -PathType Container)) {
          if (!(Test-Path $Destination)) {
              New-Item -Path $Destination -ItemType Container | Out-Null
          }
          $Destination += "\$($File.Name)"
      }
      
      # Destination is a file
      if (!(Test-Path $Destination)) {
          if ($WhatIf) {
              Write-Host "WhatIf:Copy-IfNotPresent $FilePath -> $Destination"
          } else {
              # Force creation of parent folder
              $Parent = Split-Path $Destination -Parent
              if (!(Test-Path $Parent)) { 
                  New-Item $Parent -ItemType Container | Out-Null
              }
              Copy-Item -Path $FilePath -Destination $Destination  
              Write-Verbose "Copy-IfNotPresent $FilePath -> $Destination (is absent) copying"
          }
      } else {
          Write-Verbose "Copy-IfNotPresent $Destination (is present) not copying"
      }
      }
      

      【讨论】:

        【解决方案6】:

        $source = "c:\source"

        $destination = "c:\destination"

        1. 创建要排除的文件列表,即目标中已存在的文件。
        $exclude = Get-Childitem -Recurse $destination | ForEach-Object { $_.FullName -replace [Regex]::Escape($destination ), "" }
        
        1. 递归地将所有内容从source复制到destination,不包括之前收集的文件。
        Copy-Item -Recurse -Path (Join-Path $source "*") -Destination $destination -Exclude $exclude -Force -Verbose
        
        • (Join-Path $source "*") 在末尾添加一个通配符,确保您获得 source 文件夹的子文件夹,而不是源文件夹本身。
        • 使用Force 是因为我不介意已经存在文件夹(导致错误消息)。 谨慎使用。
        • ForEach-Object { $_.FullName -replace [Regex]::Escape($destination ), "" } 将现有文件全名转换为可用作Exclude 参数的值

        【讨论】:

          【解决方案7】:

          这是一个递归脚本,它同步 2 个文件夹,忽略现有文件:

          function Copy-FilesAndFolders([string]$folderFrom, [string]$folderTo) {
              $itensFrom = Get-ChildItem $folderFrom
              foreach ($i in $itensFrom) 
              {
                  if ($i.PSIsContainer)
                  {
                      $subFolderFrom = $folderFrom + "\" + $i.BaseName
                      $subFolderTo = $folderTo + "\" + $i.BaseName
                      Copy-FilesAndFolders $subFolderFrom $subFolderTo | Out-Null
                  }
                  else
                  {
                      $from = $folderFrom + "\" + $i.Name
                      $to = $folderTo + "\" + $i.Name
                      if (!(Test-Path $from)) # only copies non-existing files
                      {
                          if (!(Test-Path $folderTo)) # if folder doesn't exist, creates it
                          {
                              New-Item -ItemType "directory" -Path $folderTo
                          }
                          Copy-Item $from $folderTo
                      }           
                  }
              }   
          }
          

          称呼它:

          Copy-FilesAndFolders "C:\FromFolder" "C:\ToFolder"
          

          【讨论】:

          • 我从新成员那里看到的更好的答案之一。非常清楚,有解释和用法(例如不仅仅是代码)。做得好!继续!
          • if (!(Test-Path $from)) # 只复制不存在的文件... $from 应该是 $to!?
          【解决方案8】:

          这里有很多很好的答案,这是我的贡献,因为它与保持 mp3 播放器与音乐库同步。

          #Tom Hubbard, 10-19-2021
          #Copy only new music to mp3 player, saves time by only copying items that don't exist on the destination.
          #Leaving the hardcoded directories and paths in here, sometimes too much variable substitution is confusing for newer PS users.
          
          #Gets all of the albums in the source directory such as your music library
          $albumsInLibrary = gci -Directory -path "C:\users\tom\OneDrive\Music" | select -ExpandProperty Name
          
          #Gets all of the albums of your destination folder, such as your mp3 player
          $albumsOnPlayer = gci -Directory -Path "e:\" | select -ExpandProperty name
          
          #For illustration, it will list the differences between the music library and the music player.
          Compare-Object -DifferenceObject $albumsInLibrary -ReferenceObject $albumsOnPlayer
          
          #Loop through each album in the library
          foreach ($album in $albumsInLibrary)
          {
              #Check to see if the music player contains this directory from the music library
              if ($albumsOnPlayer -notcontains $album)
          {
              #If the album doesn't exist on the music player, copy it and it's child items from the library to the player
              write-host "$album is not on music player, copying to music player" -ForegroundColor Cyan
              Copy-Item -path "C:\users\Tom\OneDrive\music\$album" -Recurse -Destination e:\$album
          }
          }
          

          【讨论】:

            猜你喜欢
            • 2015-07-06
            • 2022-01-10
            • 2012-03-25
            • 2019-01-27
            • 1970-01-01
            • 2019-11-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多