2017-04-21 1 views
2

폴더를 삭제하는 코드가 있는데 임시 폴더의 파일을 해당 폴더의 위치로 복사합니다. 폴더가 삭제 되었음에도 불구하고 Move-Item에서 "파일이 이미 있음"오류가 발생합니다.

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 
} 

은 내가 generated 경로에 대한 이동 품목 라인에 간헐적 인 오류, Move-Item : Cannot create a file when that file already exists.를 얻을.

두 번째 Remove-Item 문 뒤에 해킹을 추가하여이를 방지 할 수있었습니다. Start-Sleep -Seconds 10; 훌륭한 해결책은 아니지만.

OS가 실제 파일 삭제를 따라 잡기 전에 Remove-Item 문이/코드가 다음 줄로 이동한다는 것이 문제라고 가정합니다. 이상하게 보입니다. 주의 : 생성 된 폴더에는 ~ 2,500 개의 파일이 있습니다 (모두 1-100KB 사이).

폴더에 액세스하는 다른 프로세스가 없습니다. 즉,이 디렉토리가 내 AV에서 제외 된 상태에서 내 익스플로러 창 &을 검사 완료했습니다.

내가 생각했던 다른 옵션 :

  • 대신 Move-ItemCopy-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 
} 

업데이트 # 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 ... 
+1

는 별도의 작업으로 제거를 실행 고려할 것 :

여기 reuable cmdlet을로 감싸 위의 논리인가? 자체 메모리 공간에서 실행하는 오버 헤드로 인해 시간이 걸리거나 파일이 삭제 될 때까지 실제로 기다릴 것인지 때문에 문제가 "수정"되는지는 알 수 없습니다. – Matt

+0

@Matt : 작업 완료 (예 :'start-job ... wait-job | out-null; move) 뒤에 Move-Item을 대기시킬 수있는 한 별도의 작업하에 실행하면 행복 할 것입니다. -item ...') ... 도움이되는지 확인하기 위해 지금 테스트 할 것입니다 ... – JohnLBevan

+0

@Matt : 슬프게도 그 접근법에 기쁨이 없습니다 (내가 사용한 코드에 대한 수정 된 질문 참조). – JohnLBevan

답변

0

결국 나는이 해결책을 위해 해결했다; 완벽하지는 않지만 작동합니다.

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 
} 

이는 업데이트 # 2의 작업과 동일합니다. 작업의 오버 헤드 만 필요하지는 않습니다. 파일이 제거 될 때까지 반복됩니다.

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 
+0

어떻게 작동하는지 잘 모르겠습니다. 'break'는 루프에서 끊어집니다.'%'는 루프는 아니지만 cmdlet 인 Foreach-Object의 줄임말입니다. 따라서,'break' 문은 바깥 범위의 다른 것을 깨뜨릴 것입니다. 이것은 완전히 예상치 않게 될 수 있습니다. –

+0

좋은 지적; '돌아 오는 '것을'중단'으로 수정했다. – JohnLBevan

관련 문제