相当于cp -n的Powershell,即复制文件而不覆盖

我经常需要在驱动器之间复制大量的文件,而且这个过程经常被启动和停止。 在posix shell中,我可以使用cp -n不覆盖现有文件,但是在powershell中似乎没有相当于“不覆盖” 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,在开始复制之前,花费了几分钟的时间,通过已经复制的文件。

另一种方法是使用[System.IO.File]::Copy(source,dest) ,当destionation存在的时候会抛出异常,但是你必须处理异常处理+创建目录的开销,所以它很可能不会有太大的帮助

您可以直接使用.NET Exists()方法来减少路径测试中的某些PowerShell开销(2/3)。 我没有将Exists()调用封装在一个函数中,因为它增加了powershell-overhead。

 #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