我经常需要在驱动器之间复制大量文件,并且该过程经常启动和停止。在 posix shell 中,我可以使用 cp -n 来不覆盖现有文件,但似乎没有与 copy-item 等效的“不覆盖”开关在 powershell 中。
这意味着如果我必须停止并启动该进程,我必须使用
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
,但扫描已经存在的文件花了很长时间。如果我使用上面的脚本并且我正在完成一个大型 session 的一半,那么在开始复制新文件之前将会有几秒钟的暂停;使用 robocopy,在开始复制之前,它会花费几分钟时间运行已复制的文件。
最佳答案
另一种方法是使用[System.IO.File]::Copy(source,dest)
,当目标存在时,它会抛出异常,但是你必须处理以下开销异常处理+创建目录,所以它可能不会有太大帮助。
您可以直接使用 .NET Exists()
方法来削减路径测试中的一些 powershell 开销 (2/3)。我没有将 Exists()
调用包装在函数中,因为这会增加 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
关于windows - Powershell相当于cp -n,即复制文件而不覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35955289/