2

我经常需要在驱动器之间复制大量文件,并且该过程经常启动和停止。在 posix shell 中,我可以用来不覆盖现有文件,但在 powershellcp -n中似乎没有等效的“不覆盖”开关。copy-item

这意味着如果我必须停止并开始我必须使用的过程

ls -Recurse|%{
    if (-Not(test-path($_fullname.replace("D:\", "E:\")))){
        cp $_.fullname $_.fullname.replace("D:\", "E:\");
    }
}

工作正常,但如果我有一百万个文件要复制,有时会发生,我想test-path每次都必须执行一些开销。

编辑:顺便说一句,我试过robocopy.exe d:\thedir e:\thedir /XN /XO /S了,但是扫描已经存在的文件需要很长时间。如果我使用上面的脚本并且我已经完成了一个大型会话,那么在它开始复制新文件之前会有几秒钟的暂停;使用 robocopy 时,它甚至在开始复制之前就花了几分钟的时间浏览已经复制的文件。

4

1 回答 1

2

另一种方法是在目标存在时使用[System.IO.File]::Copy(source,dest)which 将引发异常,但是您必须处理异常处理 + 创建目录的开销,因此它可能无济于事。

您可以直接使用 .NETExists()方法在路径测试中减少一些 powershell 开销(2/3)。我没有将Exists()-calls 包装在一个函数中,因为这会增加 powershell 开销。

#Avoid aliases in scripts. You want people to be able to read it later
Get-ChildItem -Recurse| ForEach-Object {
    if (-Not([System.IO.File]::Exists($_fullname.replace("D:\", "E:\")) -or [System.IO.Directory]::Exists($_fullname.replace("D:\", "E:\")))){
        Copy-Item -Path $_.fullname -Destination $_.fullname.replace("D:\", "E:\")
    }
}

比较:

Measure-Command { 1..100000 | % { [System.IO.File]::Exists("C:\users\frode") -or [System.IO.Directory]::Exists("C:\users\frode") } } | Select-Object -ExpandProperty totalseconds

6,7130002

Measure-Command { 1..100000 | % { Test-Path "C:\users\frode" } } | Select-Object -ExpandProperty totalseconds

22,4492812
于 2016-03-12T10:39:28.280 回答