Сервис архивирования Amazon Web Services Glacier имеет ограничения на загрузку файлов по размеру в 4 ГБ. Чтобы обойти эту проблему и иметь возможность загружать файлы большого объема Amazon реализовал метод загрузки архивов по частям - команды initiate-multipart-upload, upload-multipart-part, complete-multipart-upload и т.п.
Я разработал PowerShell скрипт для нарезки файлов и формирования команд для инициализации, загрузки и закрытия архива в AWS Glacier.
Для работы скрипта необходимо установить на сервер, где выполняется нарезка, две программы AWS Command Line Interface и AWS Tools For Windows. Создать два файла Split-File.ps1 и Split-File.cmd с содержимым, показанным ниже.
Код скрипта Split-File.ps1:
Add-Type -Path "C:\Program Files (x86)\AWS SDK for .NET\bin\Net45\AWSSDK.Core.dll"
Add-Type -Path "C:\Program Files (x86)\AWS SDK for .NET\bin\Net45\AWSSDK.Glacier.dll"
# AWS variables
$AWSAccountID = YOUR_AWS_ID
$AWSRegion = 'YOUR_AWS_REGION'
$AWSVaultName = 'YOUR_AWS_GLACIER_VAILT_NAME'
$AWSProfileAccessKey = "YOUR_AWS_SERVICE_ACCOUNT_ACCESS_KEY"
$AWSProfileSecretKey = "YOUR_AWS_SERVICE_ACCOUNT_SECRET_KEY"
if($args[0] -eq $null) {
Write-Host "Error: No input parameter"
Break
} else {
[String] $InputFile = $args[0];
}
[Int32] $PartSize = 1073741824 # 1 GB
[Int32] $PartNumber = 1
[String[]] $PartChecksumList = @()
# ------- Split-File -------
$InputStream = [System.IO.File]::OpenRead($InputFile)
$Piece = New-Object byte[] $PartSize
While ($BytesRead = $InputStream.Read($Piece, 0, $PartSize)) {
$OutputFile = $InputFile + ".p" + $PartNumber.ToString("00")
$OutputStream = [System.IO.File]::OpenWrite($OutputFile)
$OutputStream.Write($Piece, 0, $BytesRead)
$OutputStream.Close()
$OutputStream = [System.IO.File]::OpenRead($OutputFile)
$CurrentChecksum = [Amazon.Glacier.TreeHashGenerator]::CalculateTreeHash($OutputStream)
$OutputStream.Close()
$PartChecksumList += $CurrentChecksum
$PartNumber += 1
}
$InputStream.Close()
$TreeHash = [Amazon.Glacier.TreeHashGenerator]::CalculateTreeHash([String[]]$PartChecksumList)
$OutputTreeHashFile = $InputFile + ".hash"
$TreeHash | Out-File $OutputTreeHashFile
# ------- Generate multiupload command -------
$FileDirectory = (Get-Item -Path $InputFile).DirectoryName
$FileName = (Get-Item -Path $InputFile).Name
$FileSize = (Get-Item -Path $InputFile).Length
$FileParts = Get-ChildItem $FileDirectory -Filter "$FileName.p*" | Sort-Object -Property "Name"
$MultiuploadCommandFile = $InputFile + "_Command1.txt"
Out-File -FilePath $MultiuploadCommandFile
$CommandLine = "aws glacier initiate-multipart-upload --account-id $AWSAccountID"
$CommandLine += " --vault-name $AWSVaultName --part-size $PartSize"
$CommandLine += " --archive-description ""$FileName"""
$CommandLine | Out-File -FilePath $MultiuploadCommandFile -Append
$MultiuploadCommandFile = $InputFile + "_Command2.txt"
Out-File -FilePath $MultiuploadCommandFile
"set uploadID=Put_Here_Upload_ID" | Out-File -FilePath $MultiuploadCommandFile -Append
"set uploadTreeHash=$TreeHash" | Out-File -FilePath $MultiuploadCommandFile -Append
"" | Out-File -FilePath $MultiuploadCommandFile -Append
[int] $i=1
[long] $StartByte = 0
[long] $EndByte = 0
ForEach ($FilePart in $FileParts) {
If ($i -lt $FileParts.Count) {
$EndByte = $StartByte + $PartSize - 1
} Else {
$EndByte = $FileSize - 1
}
$FilePartRange = """bytes $StartByte-$EndByte/*"""
$FilePartPath = """" + $FilePart.FullName + """"
$CommandLine = "aws glacier upload-multipart-part --account-id $AWSAccountID --vault-name $AWSVaultName"
$CommandLine +=" --upload-id %uploadID% --range $FilePartRange --body $FilePartPath"
$CommandLine | Out-File -FilePath $MultiuploadCommandFile -Append
$i++
$StartByte = $EndByte + 1
}
"" | Out-File -FilePath $MultiuploadCommandFile -Append
$CommandLine = "aws glacier complete-multipart-upload --account-id $AWSAccountID --vault-name $AWSVaultName"
$CommandLine += " --upload-id %uploadID% --archive-size $FileSize --checksum %uploadTreeHash%"
$CommandLine | Out-File -FilePath $MultiuploadCommandFile -Append
Код скрипта Split-File.cmd:
powershell.exe "%~DP0Split-File.ps1" %1
Перед запуском нарезки файла необходимо в файле Split-File.ps1 вписать данные своей учетной записи AWS с строках 5-9.
Для нарезки файла необходимо перетащить архив на скрипт Split-File.cmd, который вызовет Split-File.ps1 и подставит в качестве входного параметра путь к архиву.
Результатом работы скрипта будет:
- Коллекция частей архива по 1 ГБ (имя_архива.p01, имя_архива.p02 и т.д).
- Файл с контрольной суммой (имя_архива.hash).
- Файл с командой для инициализации закачки (имя_архива_Command1.txt).
- Файл с командами закачки чайтей архива и закрытия архива (имя_архива_Command2.txt).
Чтобы выполнить закачку разрезанного архива необходимо:
- Открыть командную строку.
- Вставить в командную строку содержимое файла имя_архива_Command1.txt.
- Из ответа сервера скопировать значение uploadID.
- В файле имя_архива_Command2.txt заменить Put_Here_Upload_ID на скопированное значение uploadID.
- Вставить в командную строку содержимое файла имя_архива_Command2.txt - начнется поочередное выполнение команд из буфера обмена - закачка частей архива.
- При успешной закачке всех частей в командную строку сервер AWS вернет значение archiveID, которое он присвоил новому архиву. В противном случае выдаст номер частей архива, загрузка которых не удалась.
