我正在开发一个项目来压缩从几个 mb 到几个 GB 大小的文件,我正在尝试使用 powershell 将它们压缩成 .zip。我遇到的主要问题是使用压缩存档对单个文件大小有 2 GB 上限,我想知道是否有另一种方法来压缩文件。
编辑:
因此,对于这个项目,我们希望实现一个系统,从 Outlook 获取 .pst 文件并将其压缩为 .zip 并将其上传到服务器。上传后,它们将从新设备上拉下来并再次提取到 .pst 文件中。
注意
此功能的进一步更新将发布到官方 GitHub 存储库 以及 PowerShell Gallery。此答案中的代码将不再维护。
非常欢迎贡献,如果您想贡献,请分叉存储库并提交包含更改的拉取请求。
Compress-Archive
的限制:
发生这种情况是因为此 cmdlet 使用“内存流”将字节保存在内存中,然后将它们写入文件。检查 cmdlet 生成的cmdlet 使用 Microsoft .NET APICompress-Archive
来压缩文件。由于底层 API 的限制,最大文件大小为 2 GB。System.IO.Compression.ZipArchive
InnerException,我们可以看到:
System.IO.IOException: Stream was too long.
at System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count)
at CallSite.Target(Closure , CallSite , Object , Object , Int32 , Object )
:
Exception calling "ReadAllBytes" with "1" argument(s): "The file is too long.
This operation is currently limited to supporting files less than 2 gigabytes in size."
巧合的是,我们也看到了同样的限制
System.Array
仅限 .NET Framework:默认情况下,数组的最大大小为 2 GB。
中还指出了另一个限制,在
这个问题
Compress-Archive
# cd to a temporary folder and
# start a Job which will write to a file
$job = Start-Job {
0..1000 | ForEach-Object {
"Iteration ${_}:" + ('A' * 1kb)
Start-Sleep -Milliseconds 200
} | Set-Content .\temp\test.txt
}
Start-Sleep -Seconds 1
# attempt to compress
Compress-Archive .\temp\test.txt -DestinationPath test.zip
# Exception:
# The process cannot access the file '..\test.txt' because it is being used by another process.
$job | Stop-Job -PassThru | Remove-Job
Remove-Item .\temp -Recurse
[FileShare] 'ReadWrite, Delete'
FileStream
。
要解决此问题,有两种解决方法:
ZipFile.CreateFromDirectory
来源必须是目录,单个文件无法压缩。
ZipFile
,则必须引用 System.IO.Compression.FileSystem
。请参阅内嵌评论。
# Only needed if using Windows PowerShell (.NET Framework):
Add-Type -AssemblyName System.IO.Compression.FileSystem
[IO.Compression.ZipFile]::CreateFromDirectory($sourceDirectory, $destinationArchive)
自己编写代码的解决方法是使用一个函数来完成创建 ZipArchive
ZipEntries
的所有手动过程。
此函数应该能够处理与 ZipFile.CreateFromDirectory
。
可以在此处找到文档以及使用示例。