Сервис архивирования 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, которое он присвоил новому архиву. В противном случае выдаст номер частей архива, загрузка которых не удалась.