我经常需要在驱动器之间复制大量的文件,而且这个过程经常被启动和停止。 在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