You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 10:05:34