PowerShell压缩归档报错:文件被其他进程占用的解决方法
PowerShell压缩大文件时出现“文件被占用”错误的解决方法
问题场景
编写的PowerShell脚本用于将输入文件夹(含子文件夹)的文件复制到目标文件夹,之后压缩输入文件夹所有文件为ZIP。但处理0-20MB大文件时报错,小文件可正常执行。脚本代码如下:
$files = Get-ChildItem -Path "\\networkdrive\RawData\1_DataRetrieved*" -Recurse # 复制ResponseTimes相关文件到指定目录 $files | Where-Object Name -Like "*ResponseTimes*" | Copy-Item -Destination "\\networkdrive\ResponseTimes\RawData_Field\2_ActionData" -Verbose # 压缩输入文件夹所有文件到ZIP $compress = @{ Path = "\\networkdrive\RawData\1_DataRetrieved\*" CompressionLevel = "Fastest" DestinationPath = "\\networkdrive\_Archive\Archive_DataRetrieved\Archive_DataRetrieved $(get-date -f yyyy-MM-dd_hhmmss).zip" } Compress-Archive @compress -Verbose
报错信息
VERBOSE: 已删除部分创建的归档文件'\eubelccfs01\REGIONAL\Drachten\R&D\SHM\RawData_Archive\Archive_DataRetrieved\Archive_DataRetrieved 2023-05-09_045227.zip',因其无法使用。
New-Object : Exception calling ".ctor" with "2" argument(s): "无法访问文件'\\networkdrive\RawData\_Archive\Archive_DataRetrieved\Archive_DataRetrieved 2023-05-09_080317.zip',因为它正被其他进程占用。" At C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:729 char:30 + ... ileStream = New-Object -TypeName System.IO.FileStream -ArgumentList $ ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
解决方法
1. 确保复制操作完全完成后再执行压缩
Copy-Item处理大文件时可能后台异步完成,导致压缩启动时文件仍被复制进程占用。改用robocopy替代,它默认等待复制完成再返回:
# 替换原Copy-Item命令为robocopy $sourceFiles = $files | Where-Object Name -Like "*ResponseTimes*" $destPath = "\\networkdrive\ResponseTimes\RawData_Field\2_ActionData" foreach ($file in $sourceFiles) { robocopy $file.DirectoryName $destPath $file.Name /NFL /NDL /NJH /NJS }
/NFL//NDL:不显示文件/目录列表/NJH//NJS:不显示作业头/作业摘要,减少输出干扰
2. 避免通配符导致的文件锁定问题
原脚本用通配符指定压缩路径,可能导致PowerShell遍历文件时保持句柄打开。改为先获取所有文件的完整路径再传入:
# 先获取所有要压缩的文件路径 $zipFiles = Get-ChildItem -Path "\\networkdrive\RawData\1_DataRetrieved" -Recurse -File | Select-Object -ExpandProperty FullName $compress = @{ Path = $zipFiles CompressionLevel = "Fastest" DestinationPath = "\\networkdrive\_Archive\Archive_DataRetrieved\Archive_DataRetrieved $(get-date -f yyyy-MM-dd_hhmmss).zip" } Compress-Archive @compress -Verbose
3. 添加重试机制应对临时占用冲突
如果是临时文件占用,添加重试逻辑,等待一段时间后再次尝试:
$maxRetries = 3 $retryDelaySeconds = 10 $success = $false for ($i=1; $i -le $maxRetries; $i++) { try { Compress-Archive @compress -Verbose -ErrorAction Stop $success = $true break } catch { Write-Warning "第$i次压缩失败,$retryDelaySeconds秒后重试:$_" Start-Sleep -Seconds $retryDelaySeconds } } if (-not $success) { Write-Error "重试$maxRetries次后仍无法完成压缩" }
4. 直接使用.NET类处理压缩(替代Compress-Archive)
Compress-Archive在网络共享上处理大文件易出现兼容性问题,改用System.IO.Compression.ZipFile类更稳定:
Add-Type -AssemblyName System.IO.Compression.FileSystem $zipPath = "\\networkdrive\_Archive\Archive_DataRetrieved\Archive_DataRetrieved $(get-date -f yyyy-MM-dd_hhmmss).zip" $sourceDir = "\\networkdrive\RawData\1_DataRetrieved" # 创建ZIP文件并添加所有文件 [System.IO.Compression.ZipFile]::CreateFromDirectory( $sourceDir, $zipPath, [System.IO.Compression.CompressionLevel]::Fastest, $true # 包含根目录下的文件(不创建额外子文件夹) )
内容的提问来源于stack exchange,提问作者Hayco
相关产品推荐
相关产品推荐

