멀티파트 업로드를 사용한 객체 업로드
멀티파트 업로드를 사용한 객체 업로드 (Uploading an object using multipart upload)
멀티파트 업로드를 사용하면 단일 객체를 프로그래밍 방식으로 Amazon S3에 업로드할 수 있어요. 각 객체는 여러 부분으로 나눠 업로드돼요. 각 부분은 객체 데이터의 연속적인 일부예요. 이 객체 부분들은 서로 독립적으로, 어떤 순서로든 업로드할 수 있어요. 일부 부분의 전송이 실패하면 다른 부분에 영향을 주지 않고 해당 부분만 다시 전송할 수 있어요. 객체의 모든 부분을 업로드한 후 Amazon S3가 이 부분들을 조합해 객체를 만들어요. 익명 사용자는 멀티파트 업로드를 시작할 수 없어요.
출처: 문서
본문
참고 멀티파트 업로드 복사 작업은 기본적으로 원본 객체에서 주석(annotation)을 복사하지 않아요. 멀티파트 업로드를 사용해 객체를 복사할 때 주석을 포함하려면(예: 약 8MB보다 큰 객체에 대해 AWS CLI
aws s3 cp명령을 사용할 때)--copy-props all을 지정해요.
추가 체크섬과 함께 멀티파트 업로드로 객체를 업로드하는 종단 간 절차는 멀티파트 업로드로 객체 업로드 및 데이터 무결성 확인 튜토리얼을 참고하세요.
다음 절은 AWS Command Line Interface 및 AWS SDK로 멀티파트 업로드를 사용하는 방법을 보여줘요.
이미지, 백업, 데이터, 동영상 등 모든 파일 유형을 S3 버킷에 업로드할 수 있어요. Amazon S3 콘솔을 사용해 업로드할 수 있는 파일의 최대 크기는 160GB예요. 160GB보다 큰 파일을 업로드하려면 AWS Command Line Interface(AWS CLI), AWS SDK 또는 Amazon S3 REST API를 사용해야 해요.
AWS Management Console로 객체를 업로드하는 방법에 대한 지침은 객체 업로드를 참고하세요.
다음은 AWS CLI를 사용한 멀티파트 업로드의 Amazon S3 작업을 설명해요.
- Initiate Multipart Upload
- Upload Part
- Upload Part (Copy)
- Complete Multipart Upload
- Abort Multipart Upload
- List Parts
- List Multipart Uploads
Amazon Simple Storage Service API Reference의 다음 절은 멀티파트 업로드의 REST API를 설명해요.
- Initiate Multipart Upload
- Upload Part
- Complete Multipart Upload
- Stop Multipart Upload
- List Parts
- List Multipart Uploads
일부 AWS SDK는 멀티파트 업로드를 완료하는 데 필요한 다양한 API 작업을 단일 작업으로 결합해 멀티파트 업로드를 단순화하는 하이 레벨 API를 제공해요. 자세한 내용은 Amazon S3에서 멀티파트 업로드를 사용한 객체 업로드 및 복사를 참고하세요.
멀티파트 업로드를 일시 중지·재개해야 하거나, 업로드 중 부분 크기를 변경해야 하거나, 데이터 크기를 미리 알지 못하는 경우에는 로우 레벨 API 메서드를 사용해요. 멀티파트 업로드용 로우 레벨 API 메서드는 추가 기능을 제공해요. 자세한 내용은 AWS SDK 사용(로우 레벨 API)을 참고하세요.
Java | .NET | JavaScript | Go | PHP | Python
AWS SDK for Java로 멀티파트 업로드를 수행하는 예시는 Amazon S3 API Reference의 AWS SDK를 사용해 Amazon S3 간 대형 파일 업로드 또는 다운로드를 참고하세요.
S3 버킷에 파일을 업로드하려면 TransferUtility 클래스를 사용해요. 파일에서 데이터를 업로드할 때는 객체의 키 이름을 제공해야 해요. 제공하지 않으면 API가 키 이름으로 파일 이름을 사용해요. 스트림에서 데이터를 업로드할 때는 객체의 키 이름을 제공해야 해요.
부분 크기, 부분을 동시에 업로드할 때의 스레드 수, 메타데이터, 스토리지 클래스 또는 ACL 같은 고급 업로드 옵션을 설정하려면 TransferUtilityUploadRequest 클래스를 사용해요.
참고 데이터 소스로 스트림을 사용하는 경우
TransferUtility클래스는 동시 업로드를 수행하지 않아요.
다음 C# 예시는 Amazon S3 버킷에 파일을 여러 부분으로 나눠 업로드해요. 다양한 TransferUtility.Upload 오버로드를 사용해 파일을 업로드하는 방법을 보여줘요. 업로드를 호출할 때마다 이전 업로드를 대체해요. 코드 예시를 설정하고 실행하는 방법에 대한 자세한 내용은 AWS SDK for .NET 개발자 가이드의 AWS SDK for .NET 시작하기를 참고하세요.
using Amazon;
using Amazon.S3;
using Amazon.S3.Transfer;
using System;
using System.IO;
using System.Threading.Tasks;
namespace Amazon.DocSamples.S3
{
class UploadFileMPUHighLevelAPITest
{
private const string bucketName = "*** provide bucket name ***";
private const string keyName = "*** provide a name for the uploaded object ***";
private const string filePath = "*** provide the full path name of the file to upload ***";
// Specify your bucket region (an example region is shown).
private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USWest2;
private static IAmazonS3 s3Client;
public static void Main()
{
s3Client = new AmazonS3Client(bucketRegion);
UploadFileAsync().Wait();
}
private static async Task UploadFileAsync()
{
try
{
var fileTransferUtility =
new TransferUtility(s3Client);
// Option 1. Upload a file. The file name is used as the object key name.
await fileTransferUtility.UploadAsync(filePath, bucketName);
Console.WriteLine("Upload 1 completed");
// Option 2. Specify object key name explicitly.
await fileTransferUtility.UploadAsync(filePath, bucketName, keyName);
Console.WriteLine("Upload 2 completed");
// Option 3. Upload data from a type of System.IO.Stream.
using (var fileToUpload =
new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
await fileTransferUtility.UploadAsync(fileToUpload,
bucketName, keyName);
}
Console.WriteLine("Upload 3 completed");
// Option 4. Specify advanced settings.
var fileTransferUtilityRequest = new TransferUtilityUploadRequest
{
BucketName = bucketName,
FilePath = filePath,
StorageClass = S3StorageClass.StandardInfrequentAccess,
PartSize = 6291456, // 6 MB.
Key = keyName,
CannedACL = S3CannedACL.PublicRead
};
fileTransferUtilityRequest.Metadata.Add("param1", "Value1");
fileTransferUtilityRequest.Metadata.Add("param2", "Value2");
await fileTransferUtility.UploadAsync(fileTransferUtilityRequest);
Console.WriteLine("Upload 4 completed");
}
catch (AmazonS3Exception e)
{
Console.WriteLine("Error encountered on server. Message:'{0}' when writing an object", e.Message);
}
catch (Exception e)
{
Console.WriteLine("Unknown encountered on server. Message:'{0}' when writing an object", e.Message);
}
}
}
}
예시: 대형 파일 업로드
import { S3Client } from "@aws-sdk/client-s3";
import { Upload } from "@aws-sdk/lib-storage";
import {
ProgressBar,
logger,
} from "@aws-doc-sdk-examples/lib/utils/util-log.js";
const twentyFiveMB = 25 * 1024 * 1024;
export const createString = (size = twentyFiveMB) => {
return "x".repeat(size);
};
/**
* Create a 25MB file and upload it in parts to the specified
* Amazon S3 bucket.
* @param {{ bucketName: string, key: string }}
*/
export const main = async ({ bucketName, key }) => {
const str = createString();
const buffer = Buffer.from(str, "utf8");
const progressBar = new ProgressBar({
description: `Uploading "${key}" to "${bucketName}"`,
barLength: 30,
});
try {
const upload = new Upload({
client: new S3Client({}),
params: {
Bucket: bucketName,
Key: key,
Body: buffer,
},
});
upload.on("httpUploadProgress", ({ loaded, total }) => {
progressBar.update({ current: loaded, total });
});
await upload.done();
} catch (caught) {
if (caught instanceof Error && caught.name === "AbortError") {
logger.error(`Multipart upload was aborted. ${caught.message}`);
} else {
throw caught;
}
}
};
예시: 대형 파일 다운로드
import { fileURLToPath } from "node:url";
import { GetObjectCommand, NoSuchKey, S3Client } from "@aws-sdk/client-s3";
import { createWriteStream, rmSync } from "node:fs";
const s3Client = new S3Client({});
const oneMB = 1024 * 1024;
export const getObjectRange = ({ bucket, key, start, end }) => {
const command = new GetObjectCommand({
Bucket: bucket,
Key: key,
Range: `bytes=${start}-${end}`,
});
return s3Client.send(command);
};
/**
* @param {string | undefined} contentRange
*/
export const getRangeAndLength = (contentRange) => {
const [range, length] = contentRange.split("/");
const [start, end] = range.split("-");
return {
start: Number.parseInt(start),
end: Number.parseInt(end),
length: Number.parseInt(length),
};
};
export const isComplete = ({ end, length }) => end === length - 1;
const downloadInChunks = async ({ bucket, key }) => {
const writeStream = createWriteStream(
fileURLToPath(new URL(`./${key}`, import.meta.url)),
).on("error", (err) => console.error(err));
let rangeAndLength = { start: -1, end: -1, length: -1 };
while (!isComplete(rangeAndLength)) {
const { end } = rangeAndLength;
const nextRange = { start: end + 1, end: end + oneMB };
const { ContentRange, Body } = await getObjectRange({
bucket,
key,
...nextRange,
});
console.log(`Downloaded bytes ${nextRange.start} to ${nextRange.end}`);
writeStream.write(await Body.transformToByteArray());
rangeAndLength = getRangeAndLength(ContentRange);
}
};
/**
* Download a large object from and Amazon S3 bucket.
*
* When downloading a large file, you might want to break it down into
* smaller pieces. Amazon S3 accepts a Range header to specify the start
* and end of the byte range to be downloaded.
*
* @param {{ bucketName: string, key: string }}
*/
export const main = async ({ bucketName, key }) => {
try {
await downloadInChunks({
bucket: bucketName,
key: key,
});
} catch (caught) {
if (caught instanceof NoSuchKey) {
console.error(`Failed to download object. No such key "${key}".`);
rmSync(key);
}
}
};
Go 코드 예시에 대한 자세한 내용은 AWS SDK를 사용해 Amazon S3 간 대형 파일 업로드 또는 다운로드를 참고하세요.
예시: 업로드 관리자를 사용해 데이터를 부분으로 나눠 동시에 업로드하는 대형 객체 업로드
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"log"
"os"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/aws/smithy-go"
)
// BucketBasics encapsulates the Amazon Simple Storage Service (Amazon S3) actions
// used in the examples.
// It contains S3Client, an Amazon S3 service client that is used to perform bucket
// and object actions.
type BucketBasics struct {
S3Client *s3.Client
}
// UploadLargeObject uses an upload manager to upload data to an object in a bucket.
// The upload manager breaks large data into parts and uploads the parts concurrently.
func (basics BucketBasics) UploadLargeObject(ctx context.Context, bucketName string, objectKey string, largeObject []byte) error {
largeBuffer := bytes.NewReader(largeObject)
var partMiBs int64 = 10
uploader := manager.NewUploader(basics.S3Client, func(u *manager.Uploader) {
u.PartSize = partMiBs * 1024 * 1024
})
_, err := uploader.Upload(ctx, &s3.PutObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectKey),
Body: largeBuffer,
})
if err != nil {
var apiErr smithy.APIError
if errors.As(err, &apiErr) && apiErr.ErrorCode() == "EntityTooLarge" {
log.Printf("Error while uploading object to %s. The object is too large.\n"+
"The maximum size for a multipart upload is 5TB.", bucketName)
} else {
log.Printf("Couldn't upload large object to %v:%v. Here's why: %v\n",
bucketName, objectKey, err)
}
} else {
err = s3.NewObjectExistsWaiter(basics.S3Client).Wait(
ctx, &s3.HeadObjectInput{Bucket: aws.String(bucketName), Key: aws.String(objectKey)}, time.Minute)
if err != nil {
log.Printf("Failed attempt to wait for object %s to exist.\n", objectKey)
}
}
return err
}
예시: 다운로드 관리자를 사용해 데이터를 부분으로 나눠 동시에 다운로드하는 대형 객체 다운로드
// DownloadLargeObject uses a download manager to download an object from a bucket.
// The download manager gets the data in parts and writes them to a buffer until all of
// the data has been downloaded.
func (basics BucketBasics) DownloadLargeObject(ctx context.Context, bucketName string, objectKey string) ([]byte, error) {
var partMiBs int64 = 10
downloader := manager.NewDownloader(basics.S3Client, func(d *manager.Downloader) {
d.PartSize = partMiBs * 1024 * 1024
})
buffer := manager.NewWriteAtBuffer([]byte{})
_, err := downloader.Download(ctx, buffer, &s3.GetObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectKey),
})
if err != nil {
log.Printf("Couldn't download large object from %v:%v. Here's why: %v\n",
bucketName, objectKey, err)
}
return buffer.Bytes(), err
}
이 주제는 AWS SDK for PHP의 하이 레벨 Aws\S3\Model\MultipartUpload\UploadBuilder 클래스를 멀티파트 파일 업로드에 사용하는 방법을 설명해요. AWS SDK for Ruby API에 대한 자세한 내용은 AWS SDK for Ruby - 버전 2를 참고하세요.
다음 PHP 예시는 Amazon S3 버킷에 파일을 업로드해요. 이 예시는 MultipartUploader 객체의 매개 변수를 설정하는 방법을 보여줘요.
require 'vendor/autoload.php';
use Aws\Exception\MultipartUploadException;
use Aws\S3\MultipartUploader;
use Aws\S3\S3Client;
$bucket = '*** Your Bucket Name ***';
$keyname = '*** Your Object Key ***';
$s3 = new S3Client([
'version' => 'latest',
'region' => 'us-east-1'
]);
// Prepare the upload parameters.
$uploader = new MultipartUploader($s3, '/path/to/large/file.zip', [
'bucket' => $bucket,
'key' => $keyname
]);
// Perform the upload.
try {
$result = $uploader->upload();
echo "Upload complete: {$result['ObjectURL']}" . PHP_EOL;
} catch (MultipartUploadException $e) {
echo $e->getMessage() . PHP_EOL;
}
다음 예시는 하이 레벨 멀티파트 업로드 Python API(TransferManager 클래스)를 사용해 객체를 업로드해요.
import sys
import threading
import boto3
from boto3.s3.transfer import TransferConfig
MB = 1024 * 1024
s3 = boto3.resource("s3")
class TransferCallback:
"""
Handle callbacks from the transfer manager.
The transfer manager periodically calls the __call__ method throughout
the upload and download process so that it can take action, such as
displaying progress to the user and collecting data about the transfer.
"""
def __init__(self, target_size):
self._target_size = target_size
self._total_transferred = 0
self._lock = threading.Lock()
self.thread_info = {}
def __call__(self, bytes_transferred):
"""
The callback method that is called by the transfer manager.
Display progress during file transfer and collect per-thread transfer
data. This method can be called by multiple threads, so shared instance
data is protected by a thread lock.
"""
thread = threading.current_thread()
with self._lock:
self._total_transferred += bytes_transferred
if thread.ident not in self.thread_info.keys():
self.thread_info[thread.ident] = bytes_transferred
else:
self.thread_info[thread.ident] += bytes_transferred
target = self._target_size * MB
sys.stdout.write(
f"\r{self._total_transferred} of {target} transferred "
f"({(self._total_transferred / target) * 100:.2f}%)."
)
sys.stdout.flush()
def upload_with_default_configuration(
local_file_path, bucket_name, object_key, file_size_mb
):
"""
Upload a file from a local folder to an Amazon S3 bucket, using the default
configuration.
"""
transfer_callback = TransferCallback(file_size_mb)
s3.Bucket(bucket_name).upload_file(
local_file_path, object_key, Callback=transfer_callback
)
return transfer_callback.thread_info
def upload_with_chunksize_and_meta(
local_file_path, bucket_name, object_key, file_size_mb, metadata=None
):
"""
Upload a file from a local folder to an Amazon S3 bucket, setting a
multipart chunk size and adding metadata to the Amazon S3 object.
The multipart chunk size controls the size of the chunks of data that are
sent in the request. A smaller chunk size typically results in the transfer
manager using more threads for the upload.
The metadata is a set of key-value pairs that are stored with the object
in Amazon S3.
"""
transfer_callback = TransferCallback(file_size_mb)
config = TransferConfig(multipart_chunksize=1 * MB)
extra_args = {"Metadata": metadata} if metadata else None
s3.Bucket(bucket_name).upload_file(
local_file_path,
object_key,
Config=config,
ExtraArgs=extra_args,
Callback=transfer_callback,
)
return transfer_callback.thread_info
def upload_with_high_threshold(local_file_path, bucket_name, object_key, file_size_mb):
"""
Upload a file from a local folder to an Amazon S3 bucket, setting a
multipart threshold larger than the size of the file.
Setting a multipart threshold larger than the size of the file results
in the transfer manager sending the file as a standard upload instead of
a multipart upload.
"""
transfer_callback = TransferCallback(file_size_mb)
config = TransferConfig(multipart_threshold=file_size_mb * 2 * MB)
s3.Bucket(bucket_name).upload_file(
local_file_path, object_key, Config=config, Callback=transfer_callback
)
return transfer_callback.thread_info
def upload_with_sse(
local_file_path, bucket_name, object_key, file_size_mb, sse_key=None
):
"""
Upload a file from a local folder to an Amazon S3 bucket, adding server-side
encryption with customer-provided encryption keys to the object.
When this kind of encryption is specified, Amazon S3 encrypts the object
at rest and allows downloads only when the expected encryption key is
provided in the download request.
"""
transfer_callback = TransferCallback(file_size_mb)
if sse_key:
extra_args = {"SSECustomerAlgorithm": "AES256", "SSECustomerKey": sse_key}
else:
extra_args = None
s3.Bucket(bucket_name).upload_file(
local_file_path, object_key, ExtraArgs=extra_args, Callback=transfer_callback
)
return transfer_callback.thread_info
def download_with_default_configuration(
bucket_name, object_key, download_file_path, file_size_mb
):
"""
Download a file from an Amazon S3 bucket to a local folder, using the
default configuration.
"""
transfer_callback = TransferCallback(file_size_mb)
s3.Bucket(bucket_name).Object(object_key).download_file(
download_file_path, Callback=transfer_callback
)
return transfer_callback.thread_info
def download_with_single_thread(
bucket_name, object_key, download_file_path, file_size_mb
):
"""
Download a file from an Amazon S3 bucket to a local folder, using a
single thread.
"""
transfer_callback = TransferCallback(file_size_mb)
config = TransferConfig(use_threads=False)
s3.Bucket(bucket_name).Object(object_key).download_file(
download_file_path, Config=config, Callback=transfer_callback
)
return transfer_callback.thread_info
def download_with_high_threshold(
bucket_name, object_key, download_file_path, file_size_mb
):
"""
Download a file from an Amazon S3 bucket to a local folder, setting a
multipart threshold larger than the size of the file.
Setting a multipart threshold larger than the size of the file results
in the transfer manager sending the file as a standard download instead
of a multipart download.
"""
transfer_callback = TransferCallback(file_size_mb)
config = TransferConfig(multipart_threshold=file_size_mb * 2 * MB)
s3.Bucket(bucket_name).Object(object_key).download_file(
download_file_path, Config=config, Callback=transfer_callback
)
return transfer_callback.thread_info
def download_with_sse(
bucket_name, object_key, download_file_path, file_size_mb, sse_key
):
"""
Download a file from an Amazon S3 bucket to a local folder, adding a
customer-provided encryption key to the request.
When this kind of encryption is specified, Amazon S3 encrypts the object
at rest and allows downloads only when the expected encryption key is
provided in the download request.
"""
transfer_callback = TransferCallback(file_size_mb)
if sse_key:
extra_args = {"SSECustomerAlgorithm": "AES256", "SSECustomerKey": sse_key}
else:
extra_args = None
s3.Bucket(bucket_name).Object(object_key).download_file(
download_file_path, ExtraArgs=extra_args, Callback=transfer_callback
)
return transfer_callback.thread_info
로우 레벨 API 사용 (Using the AWS SDKs)
AWS SDK는 멀티파트 업로드를 위한 Amazon S3 REST API를 밀접하게 반영하는 로우 레벨 API를 노출해요(Amazon S3에서 멀티파트 업로드를 사용한 객체 업로드 및 복사 참고). 멀티파트 업로드를 일시 중지·재개해야 하거나, 업로드 중 부분 크기를 변경해야 하거나, 업로드 데이터의 크기를 미리 알지 못하는 경우에는 로우 레벨 API를 사용해요. 이런 요구 사항이 없으면 하이 레벨 API를 사용해요(AWS SDK 사용(하이 레벨 API) 참고).
Java | .NET | PHP
다음 예시는 로우 레벨 Java 클래스를 사용해 파일을 업로드하는 방법을 보여줘요. 다음 단계를 수행해요.
AmazonS3Client.initiateMultipartUpload()메서드를 사용해 멀티파트 업로드를 시작하고InitiateMultipartUploadRequest객체를 전달해요.AmazonS3Client.initiateMultipartUpload()메서드가 반환하는 업로드 ID를 저장해요. 이 업로드 ID를 이후의 각 멀티파트 업로드 작업에 제공해요.- 객체의 부분을 업로드해요. 각 부분에 대해
AmazonS3Client.uploadPart()메서드를 호출해요.UploadPartRequest객체를 사용해 부분 업로드 정보를 제공해요. 각 부분에 대해AmazonS3Client.uploadPart()메서드 응답의 ETag를 목록에 저장해요. 이 ETag 값을 사용해 멀티파트 업로드를 완료해요. AmazonS3Client.completeMultipartUpload()메서드를 호출해 멀티파트 업로드를 완료해요.
예시 작동하는 샘플을 만들고 테스트하는 방법에 대한 지침은 AWS SDK for Java 개발자 가이드의 시작하기를 참고하세요.
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class LowLevelMultipartUpload {
public static void main(String[] args) throws IOException {
Regions clientRegion = Regions.DEFAULT_REGION;
String bucketName = "*** Bucket name ***";
String keyName = "*** Key name ***";
String filePath = "*** Path to file to upload ***";
File file = new File(filePath);
long contentLength = file.length();
long partSize = 5 * 1024 * 1024; // Set part size to 5 MB.
try {
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withRegion(clientRegion)
.withCredentials(new ProfileCredentialsProvider())
.build();
// Create a list of ETag objects. You retrieve ETags for each object part
// uploaded,
// then, after each individual part has been uploaded, pass the list of ETags to
// the request to complete the upload.
List<PartETag> partETags = new ArrayList<PartETag>();
// Initiate the multipart upload.
InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName, keyName);
InitiateMultipartUploadResult initResponse = s3Client.initiateMultipartUpload(initRequest);
// Upload the file parts.
long filePosition = 0;
for (int i = 1; filePosition < contentLength; i++) {
// Because the last part could be less than 5 MB, adjust the part size as
// needed.
partSize = Math.min(partSize, (contentLength - filePosition));
// Create the request to upload a part.
UploadPartRequest uploadRequest = new UploadPartRequest()
.withBucketName(bucketName)
.withKey(keyName)
.withUploadId(initResponse.getUploadId())
.withPartNumber(i)
.withFileOffset(filePosition)
.withFile(file)
.withPartSize(partSize);
// Upload the part and add the response's ETag to our list.
UploadPartResult uploadResult = s3Client.uploadPart(uploadRequest);
partETags.add(uploadResult.getPartETag());
filePosition += partSize;
}
// Complete the multipart upload.
CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(bucketName, keyName,
initResponse.getUploadId(), partETags);
s3Client.completeMultipartUpload(compRequest);
} catch (AmazonServiceException e) {
// The call was transmitted successfully, but Amazon S3 couldn't process
// it, so it returned an error response.
e.printStackTrace();
} catch (SdkClientException e) {
// Amazon S3 couldn't be contacted for a response, or the client
// couldn't parse the response from Amazon S3.
e.printStackTrace();
}
}
}
다음 C# 예시는 로우 레벨 SDK for .NET 멀티파트 업로드 API를 사용해 S3 버킷에 파일을 업로드하는 방법을 보여줘요. Amazon S3 멀티파트 업로드에 대한 정보는 Amazon S3에서 멀티파트 업로드를 사용한 객체 업로드 및 복사를 참고하세요.
참고 SDK for .NET API로 대형 객체를 업로드할 때 데이터가 요청 스트림에 쓰이는 동안 시간 초과가 발생할 수 있어요.
UploadPartRequest를 사용해 명시적 시간 초과를 설정할 수 있어요.
다음 C# 예시는 로우 레벨 멀티파트 업로드 API를 사용해 S3 버킷에 파일을 업로드해요. 코드 예시를 설정하고 실행하는 방법에 대한 자세한 내용은 AWS SDK for .NET 개발자 가이드의 AWS SDK for .NET 시작하기를 참고하세요.
using Amazon;
using Amazon.Runtime;
using Amazon.S3;
using Amazon.S3.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace Amazon.DocSamples.S3
{
class UploadFileMPULowLevelAPITest
{
private const string bucketName = "*** provide bucket name ***";
private const string keyName = "*** provide a name for the uploaded object ***";
private const string filePath = "*** provide the full path name of the file to upload ***";
// Specify your bucket region (an example region is shown).
private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USWest2;
private static IAmazonS3 s3Client;
public static void Main()
{
s3Client = new AmazonS3Client(bucketRegion);
Console.WriteLine("Uploading an object");
UploadObjectAsync().Wait();
}
private static async Task UploadObjectAsync()
{
// Create list to store upload part responses.
List<UploadPartResponse> uploadResponses = new List<UploadPartResponse>();
// Setup information required to initiate the multipart upload.
InitiateMultipartUploadRequest initiateRequest = new InitiateMultipartUploadRequest
{
BucketName = bucketName,
Key = keyName
};
// Initiate the upload.
InitiateMultipartUploadResponse initResponse =
await s3Client.InitiateMultipartUploadAsync(initiateRequest);
// Upload parts.
long contentLength = new FileInfo(filePath).Length;
long partSize = 5 * (long)Math.Pow(2, 20); // 5 MB
try
{
Console.WriteLine("Uploading parts");
long filePosition = 0;
for (int i = 1; filePosition < contentLength; i++)
{
UploadPartRequest uploadRequest = new UploadPartRequest
{
BucketName = bucketName,
Key = keyName,
UploadId = initResponse.UploadId,
PartNumber = i,
PartSize = partSize,
FilePosition = filePosition,
FilePath = filePath
};
// Track upload progress.
uploadRequest.StreamTransferProgress +=
new EventHandler<StreamTransferProgressArgs>(UploadPartProgressEventCallback);
// Upload a part and add the response to our list.
uploadResponses.Add(await s3Client.UploadPartAsync(uploadRequest));
filePosition += partSize;
}
// Setup to complete the upload.
CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest
{
BucketName = bucketName,
Key = keyName,
UploadId = initResponse.UploadId
};
completeRequest.AddPartETags(uploadResponses);
// Complete the upload.
CompleteMultipartUploadResponse completeUploadResponse =
await s3Client.CompleteMultipartUploadAsync(completeRequest);
}
catch (Exception exception)
{
Console.WriteLine("An AmazonS3Exception was thrown: { 0}", exception.Message);
// Abort the upload.
AbortMultipartUploadRequest abortMPURequest = new AbortMultipartUploadRequest
{
BucketName = bucketName,
Key = keyName,
UploadId = initResponse.UploadId
};
await s3Client.AbortMultipartUploadAsync(abortMPURequest);
}
}
public static void UploadPartProgressEventCallback(object sender, StreamTransferProgressArgs e)
{
// Process event.
Console.WriteLine("{0}/{1}", e.TransferredBytes, e.TotalBytes);
}
}
}
이 주제는 AWS SDK for PHP 버전 3의 로우 레벨 uploadPart 메서드를 사용해 파일을 여러 부분으로 나눠 업로드하는 방법을 보여줘요. AWS SDK for Ruby API에 대한 자세한 내용은 AWS SDK for Ruby - 버전 2를 참고하세요.
다음 PHP 예시는 로우 레벨 PHP API 멀티파트 업로드를 사용해 Amazon S3 버킷에 파일을 업로드해요.
require 'vendor/autoload.php';
use Aws\S3\Exception\S3Exception;
use Aws\S3\S3Client;
$bucket = '*** Your Bucket Name ***';
$keyname = '*** Your Object Key ***';
$filename = '*** Path to and Name of the File to Upload ***';
$s3 = new S3Client([
'version' => 'latest',
'region' => 'us-east-1'
]);
$result = $s3->createMultipartUpload([
'Bucket' => $bucket,
'Key' => $keyname,
'StorageClass' => 'REDUCED_REDUNDANCY',
'Metadata' => [
'param1' => 'value 1',
'param2' => 'value 2',
'param3' => 'value 3'
]
]);
$uploadId = $result['UploadId'];
// Upload the file in parts.
try {
$file = fopen($filename, 'r');
$partNumber = 1;
while (!feof($file)) {
$result = $s3->uploadPart([
'Bucket' => $bucket,
'Key' => $keyname,
'UploadId' => $uploadId,
'PartNumber' => $partNumber,
'Body' => fread($file, 5 * 1024 * 1024),
]);
$parts['Parts'][$partNumber] = [
'PartNumber' => $partNumber,
'ETag' => $result['ETag'],
];
$partNumber++;
echo "Uploading part $partNumber of $filename." . PHP_EOL;
}
fclose($file);
} catch (S3Exception $e) {
$result = $s3->abortMultipartUpload([
'Bucket' => $bucket,
'Key' => $keyname,
'UploadId' => $uploadId
]);
echo "Upload of $filename failed." . PHP_EOL;
}
// Complete the multipart upload.
$result = $s3->completeMultipartUpload([
'Bucket' => $bucket,
'Key' => $keyname,
'UploadId' => $uploadId,
'MultipartUpload' => $parts,
]);
$url = $result['Location'];
echo "Uploaded $filename to $url." . PHP_EOL;
AWS SDK for Ruby 버전 3은 Amazon S3 멀티파트 업로드를 두 가지 방식으로 지원해요. 첫 번째 옵션은 관리형 파일 업로드(managed file uploads)를 사용하는 방식이에요. 자세한 내용은 AWS Developer Blog의 Amazon S3에 파일 업로드를 참고하세요. 관리형 파일 업로드는 버킷에 파일을 업로드할 때 권장되는 방식이에요. 다음과 같은 이점을 제공해요.
- 15MB보다 큰 객체의 멀티파트 업로드를 관리해요.
- 인코딩 문제를 피하기 위해 파일을 올바르게 바이너리 모드로 열어요.
- 대형 객체의 부분을 병렬로 업로드하기 위해 여러 스레드를 사용해요.
또는 다음 멀티파트 업로드 클라이언트 작업을 직접 사용할 수 있어요.
- create_multipart_upload – 멀티파트 업로드를 시작하고 업로드 ID를 반환해요.
- upload_part – 멀티파트 업로드에서 부분을 업로드해요.
- upload_part_copy – 기존 객체에서 데이터를 복사해 부분을 업로드해요.
- complete_multipart_upload – 이전에 업로드한 부분을 조합해 멀티파트 업로드를 완료해요.
- abort_multipart_upload – 멀티파트 업로드를 중지해요.