Joh*_*van 5 directory powershell file windows-7-x64 powershell-5.0
我有一些代码删除一个文件夹,然后将文件从一个临时目录复制到该文件夹所在的位置。
Remove-Item -Path '.\index.html' -Force
Remove-Item -Path '.\generated' -Force -Recurse #folder containing generated files
#Start-Sleep -Seconds 10 #uncommenting this line fixes the issue
#$tempDir contains index.html and a sub folder, "generated", which contains additional files.
#i.e. we're replacing the content we just deleted with new versions.
Get-ChildItem -Path $tempDir | %{
Move-Item -Path $_.FullName -Destination $RelativePath -Force
}
Run Code Online (Sandbox Code Playgroud)
Move-Item : Cannot create a file when that file already exists.
在generated
路径的“移动项”行上出现间歇性错误。
我已经可以通过Start-Sleep -Seconds 10
在第二个Remove-Item
声明之后添加一个hacky来防止这种情况;尽管这不是一个很好的解决方案。
我认为问题在于,在操作系统赶上实际文件删除之前,Remove-Item语句完成/代码移至下一行。尽管这看起来很奇怪/令人担忧。注意:生成的文件夹中大约有2500个文件(全部在1-100 KB之间)。
没有其他进程可以访问文件夹(即,我什至已经关闭了资源管理器窗口并测试了将该目录从我的AV中排除)。
我考虑过其他选择:
使用Copy-Item
代替Move-Item
。我不喜欢这样,因为它需要在不需要文件时创建新文件(即,副本比移动慢)...比我当前的睡眠技巧快;但还是不理想。
删除文件而不是文件夹,然后遍历子文件夹并将文件复制到新位置。这可以工作,但是对于一些应该很简单的事情来说,要编写更多的代码。所以我不想追求这种选择。
Robocopy可以解决问题。但我希望使用纯PowerShell解决方案。如果没有干净的解决方案,我将最终选择此选项。
题
更新资料
在单独的作业中运行删除操作(即使用下面的代码)不能解决问题。
Start-Job -ScriptBlock {
Remove-Item -Path '.\index.html' -Force
Remove-Item -Path '.\generated' -Force -Recurse #folder containing generated files
} | Wait-Job | Out-Null
#$tempDir contains index.html and a sub folder, "generated", which contains additional files.
#i.e. we're replacing the content we just deleted with new versions.
Get-ChildItem -Path $tempDir | %{
Move-Item -Path $_.FullName -Destination $RelativePath -Force
}
Run Code Online (Sandbox Code Playgroud)
更新#2
添加这项工作;即我们不等待固定的时间,而是等待路径被删除/每秒检查一次。如果30秒钟后仍未将其删除,我们认为它不会被删除。因此请继续进行下去(这将导致move-item
抛出将在其他地方处理的错误)。
# ... remove-item code ...
Start-Job -ScriptBlock {
param($Path)
while(Test-Path $Path){start-sleep -Seconds 1}
} -ArgumentList '.\generated' | Wait-Job -Timeout 30 | Out-Null
# ... move-item code ...
Run Code Online (Sandbox Code Playgroud)
最终我选择了这个解决方案;并不完美,但它有效。
Remove-Item -Path '.\index.html' -Force
Remove-Item -Path '.\generated' -Force -Recurse #folder containing generated files
#wait until the .\generated directory is full removed; or until ~30 seconds has elapsed
1..30 | %{
if (-not (Test-Path -Path '.\generated' -PathType Container)) {break;}
Start-Sleep -Seconds 1
}
Get-ChildItem -Path $tempDir | %{
Move-Item -Path $_.FullName -Destination $RelativePath -Force
}
Run Code Online (Sandbox Code Playgroud)
这与问题更新 #2 中的工作相同;只是不需要工作的开销;只是循环直到文件被删除。
以下是封装为可重用 cmdlet 的上述逻辑:
function Wait-Item {
[CmdletBinding()]
param (
[Parameter(Mandatory, ValueFromPipeline, HelpMessage = 'The path of the item you wish to wait for')]
[string]$Path
,
[Parameter(HelpMessage = 'How many seconds to wait for the item before giving up')]
[ValidateRange(1,[int]::MaxValue)]
[int]$TimeoutSeconds = 30
,
[Parameter(HelpMessage = 'By default the function waits for an item to appear. Adding this switch causes us to wait for the item to be removed.')]
[switch]$Remove
)
process {
[bool]$timedOut = $true
1..$TimeoutSeconds | %{
if ((Test-Path -Path $Path) -ne ($Remove.IsPresent)){$timedOut=$false; return;}
Start-Sleep -Seconds 1
}
if($timedOut) {
Write-Error "Wait-Item timed out after $TimeoutSeconds waiting for item '$Path'"
}
}
}
#example usage:
Wait-Item -Path '.\generated' -TimeoutSeconds 30 -Remove
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4544 次 |
最近记录: |