최신 업데이트:2025-08-18 15:54:16
CDNetworks 오브젝트 스토리지에서 사용자가 직접적으로 다루는 기본 데이터 단위는 오브젝트(Object)입니다. Java SDK는 다양한 오브젝트 업로드 인터페이스를 제공하여 아래와 같은 여러 방식으로 오브젝트를 업로드할 수 있습니다.
SDK는 0KB에서 최대 5GB까지 크기의 오브젝트 업로드를 지원합니다. 스트림 업로드와 파일 업로드 모두 콘텐츠 크기는 5GB를 초과할 수 없습니다. 5GB보다 큰 파일 업로드 시에는 멀티파트 업로드 기능을 사용해야 하며, 이때 각 파트의 크기는 5GB를 넘을 수 없습니다. 폼 기반 업로드는 브라우저에서 HTML Form을 통해 오브젝트를 업로드하는 방식입니다.
오브젝트 업로드 시 익명 읽기 권한을 부여하면, 업로드 성공 후 해당 오브젝트는 공개 링크를 통해 접근이 가능합니다. 오브젝트 링크 형식은 https://bucket-name.domain/folder-path/object-name 입니다. 오브젝트가 버킷의 루트 디렉터리에 저장된 경우 폴더 경로는 링크에서 생략할 수 있습니다.
스트림 업로드는 java.io.InputStream을 데이터 소스로 사용합니다. WosClient.putObject를 이용하여 데이터 스트림을 업로드할 수 있습니다. 아래 예시는 스트림을 통한 업로드 방법을 보여줍니다.
// 문자열(바이트 배열) 업로드
String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
// WosClient 인스턴스 생성
WosClient wosClient = new WosClient(ak, sk, endPoint, regionName);
String content = "Hello WOS";
wosClient.putObject("bucketname", "objectname", new ByteArrayInputStream(content.getBytes()));
// 네트워크 스트림 업로드
InputStream inputStream = new URL("http://www.a.com").openStream();
wosClient.putObject("bucketname", "objectname", inputStream);
// 파일 스트림 업로드
FileInputStream fis = new FileInputStream(new File("localfile")); // 전체 파일 경로 지정
wosClient.putObject("bucketname", "objectname", fis);
참고:
- 로컬 파일의 경우 파일 스트림보다는 파일 업로드 방식을 권장합니다.
- 대용량 파일의 경우 멀티파트 업로드를 사용하세요.
- 업로드 파일 최대 크기는 5GB입니다.
파일 업로드는 로컬 파일을 오브젝트의 원본 데이터로 사용합니다. 아래 예시는 파일 업로드 방법을 보여줍니다.
String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
// WosClient 인스턴스 생성
WosClient wosClient = new WosClient(ak, sk, endPoint, regionName);
wosClient.putObject("bucketname", "objectname", new File("localfile")); // 전체 파일 경로 지정
참고: 업로드 파일 최대 크기는 5GB입니다.
CDNetworks 오브젝트 스토리지에서는 폴더 개념이 따로 존재하지 않으며, 실제로는 모든 데이터가 오브젝트로 저장됩니다. 폴더 생성이란 /로 끝나는 이름의 0바이트 오브젝트를 생성하는 것을 의미합니다. 이렇게 생성된 오브젝트는 일반 오브젝트와 동일하게 다운로드/삭제할 수 있으며, 콘솔에서는 폴더처럼 표시됩니다.
String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
// WosClient 인스턴스 생성
WosClient wosClient = new WosClient(ak, sk, endPoint, regionName);
final String keySuffixWithSlash = "parent_directory/";
wosClient.putObject("bucketname", keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
// 폴더 내 오브젝트 생성
wosClient.putObject("bucketname", keySuffixWithSlash + "objectname", new ByteArrayInputStream("Hello WOS".getBytes()));
참고:
- 폴더 생성은 이름이
/로 끝나는 0바이트 오브젝트를 만드는 것입니다.- 계층 구조 폴더를 만들 때는 마지막 레벨만 생성하면 됩니다. 예)
src1/src2/src3/생성 시src1/src2/src3/만 생성하면 되며, 상위 디렉터리들은 별도로 만들 필요가 없습니다.
오브젝트 업로드 시 메타데이터를 함께 지정할 수 있습니다. 메타데이터에는 오브젝트 길이, MIME 타입, MD5 해시(유효성 검증용), 스토리지 클래스, 사용자 정의 메타데이터 등이 포함됩니다. 스트림, 파일, 멀티파트, 복사 업로드 등 모든 업로드 방식에서 메타데이터를 지정할 수 있습니다.
아래 표는 각 필드의 설명입니다:
| 이름 | 설명 | 기본값 |
|---|---|---|
| Content Length (Content-Length) |
업로드 오브젝트의 길이. 파일/스트림 크기를 초과할 수 없으며, 크기를 초과할 경우 초과분은 무시됨. | 실제 스트림 또는 파일 크기 |
| MIME Type (Content-Type) |
오브젝트/파일 타입 또는 웹페이지 인코딩. 브라우저가 오브젝트를 어떻게 처리할지 결정함. | application/octet-stream |
| MD5 Value (Content-MD5) |
오브젝트 MD5 해시(Base64 인코딩). 서버에서 업로드 데이터 무결성 검증에 사용. | 설정 안 함 |
| Storage Class | 오브젝트의 스토리지 클래스. 성능 및 비용 최적화 목적. 지정하지 않으면 버킷과 동일한 값 사용. | 버킷의 스토리지 클래스 |
| Custom User Metadata | 사용자 정의 속성. 오브젝트를 개인화하여 관리할 수 있음. | 설정 안 함 |
ObjectMetadata.setContentLength를 사용하여 오브젝트 길이 지정이 가능합니다. 예시:
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(1024 * 1024L); // 1MB
wosClient.putObject("bucketname", "objectname", new File("localfile"), metadata);
ObjectMetadata.setContentType를 사용하면 MIME 타입을 지정할 수 있습니다. 예시:
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType("image/jpeg");
wosClient.putObject("bucketname", "objectname.jpg", new File("localimage.jpg"), metadata);
참고: MIME 타입을 지정하지 않으면, SDK가 확장자에 따라 자동 추론합니다. (예:
.xml은application/xml,.html은text/html등)
ObjectMetadata.setContentMd5로 오브젝트의 MD5 값을 지정합니다. 예시:
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentMd5("your md5 which should be encoded by base64");
wosClient.putObject("bucketname", "objectname", new File("localimage.jpg"), metadata);
참고:
- MD5 값은 Base64로 인코딩되어야 합니다.
- 서버는 업로드된 데이터의 MD5와 지정된 MD5가 다를 경우 업로드를 400 오류로 실패 처리합니다.
- MD5를 설정하지 않으면 서버가 이 검증을 생략합니다.
- MD5 값은
WosClient.base64Md5로 계산할 수 있습니다.
ObjectMetadata.setObjectStorageClass로 스토리지 클래스를 지정할 수 있습니다. 예시:
ObjectMetadata metadata = new ObjectMetadata();
metadata.setObjectStorageClass(StorageClassEnum.ia); // IA(Infrequent Access)로 저장
wosClient.putObject("bucketname", "objectname", new File("localfile"), metadata);
참고:
- 지정하지 않으면 오브젝트의 스토리지 클래스는 버킷의 클래스와 동일합니다.
- 스토리지 클래스는 3종류이며, 의미는 버킷의 스토리지 클래스와 같습니다.
- Archive 클래스 오브젝트는 다운로드 전 반드시 복원이 필요합니다.
ObjectMetadata.addUserMetadata로 사용자 정의 메타데이터를 지정할 수 있습니다. 예시:
ObjectMetadata metadata = new ObjectMetadata();
metadata.addUserMetadata("property1", "property-value1");
metadata.getMetadata().put("property2", "property-value2");
wosClient.putObject("bucketname", "objectname", new File("localfile"), metadata);
참고:
- 위 예시에서는
property1과property2라는 두 개의 사용자 정의 메타데이터를 등록하였습니다.- 여러 개의 메타데이터 설정 가능하며, 총 크기가 8KB를 넘을 수 없습니다.
WosClient.getObjectMetadata를 통해 사용자 정의 메타데이터 조회가 가능합니다.WosClient.getObject로 오브젝트 다운로드 시에도 메타데이터가 출력됩니다.
멀티파트 업로드는 아래와 같은 상황에서 권장됩니다.
장점:
구현 단계:
먼저 멀티파트 업로드를 초기화하고, 관련 파라미터를 설정하여 Upload ID를 획득합니다. 이 Upload ID는 이후 업로드/취소/조회 등에 반드시 필요합니다.
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest("bucketname", "objectname");
ObjectMetadata metadata = new ObjectMetadata();
metadata.addUserMetadata("property", "property-value");
metadata.setContentType("text/plain");
request.setMetadata(metadata);
InitiateMultipartUploadResult result = wosClient.initiateMultipartUpload(request);
String uploadId = result.getUploadId();
System.out.println("\t" + uploadId);
참고:
- InitiateMultipartUploadRequest를 통해 오브젝트 이름 및 버킷 지정
- MIME 타입, 스토리지 클래스, 사용자 지정 메타데이터 등 지정 가능
InitiateMultipartUploadResult.getUploadId로 후속 작업에 고유하게 사용되는 Upload ID 확인
초기화 이후 오브젝트 이름 및 Upload ID를 사용하여 파트를 업로드합니다. 각 파트는 파트 번호(1~10000)로 고유 식별되며, 파트 번호의 오름차순으로 병합됩니다. 동일 파트 번호로 다시 업로드할 경우 기존 내용이 덮어쓰여집니다. 마지막 파트를 제외한 모든 파트는 100KB~5GB, 마지막 파트는 0~5GB여야 하며, 각 파트는 순서 무관하게, 혹은 서로 다른 프로세스, 머신에서 병렬 업로드할 수 있습니다.
List<PartEtag> partEtags = new ArrayList<PartEtag>();
// 첫 번째 파트 업로드
UploadPartRequest request = new UploadPartRequest("bucketname", "objectname");
request.setUploadId(uploadId);
request.setPartNumber(1);
request.setFile(new File("localfile"));
request.setPartSize(5 * 1024 * 1024L);
UploadPartResult result = wosClient.uploadPart(request);
partEtags.add(new PartEtag(result.getEtag(), result.getPartNumber()));
// 두 번째 파트 업로드
request = new UploadPartRequest("bucketname", "objectname");
request.setUploadId(uploadId);
request.setPartNumber(2);
request.setFile(new File("localfile"));
request.setOffset(5 * 1024 * 1024L);
request.setPartSize(5 * 1024 * 1024L);
result = wosClient.uploadPart(request);
partEtags.add(new PartEtag(result.getEtag(), result.getPartNumber()));
참고:
- 마지막 파트를 제외한 모든 파트는 100KB 이상이어야 합니다(최종 병합 시 검증).
- 서버에서 각 파트의 ETag(MD5)가 반환됩니다.
- 무결성 검증 필요 시 UploadPartRequest.setAttachMd5(true)로 SDK가 MD5 자동 생성/검증(로컬 파일만 지원)하도록 할 수 있습니다. (ContentMd5 직접 지정시 setAttachMd5는 무시)
- 파트 번호 범위는 1~10000. 벗어나면 400 오류 발생.
모든 파트 업로드가 끝나면 각 파트 번호와 ETag를 모아 최종 병합 API를 호출합니다. 서버는 모든 파트를 검증한 후 업로드를 마칩니다.
List<PartEtag> partEtags = new ArrayList<PartEtag>();
// partEtags에 각 파트의 번호 및 ETag를 채움
CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest("bucketname", "objectname", uploadId, partEtags);
wosClient.completeMultipartUpload(completeRequest);
참고:
- partEtags에는 업로드한 모든 파트의 번호/ETag가 포함되어야 하며, 연속되지 않아도 무방합니다.
멀티파트 업로드의 주된 장점은 대용량 파일의 더 빠르고 안정적인 업로드입니다. 아래는 병렬 업로드 방법 예시입니다.
// 초기화는 생략
ExecutorService executorService = Executors.newFixedThreadPool(20);
final File largeFile = new File("localfile");
long partSize = 100 * 1024 * 1024L;
long fileSize = largeFile.length();
long partCount = fileSize % partSize == 0 ? fileSize / partSize : fileSize / partSize + 1;
final List<PartEtag> partEtags = Collections.synchronizedList(new ArrayList<PartEtag>());
for (int i = 0; i < partCount; i++) {
final long offset = i * partSize;
final long currPartSize = (i + 1 == partCount) ? fileSize - offset : partSize;
final int partNumber = i + 1;
executorService.execute(() -> {
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(bucketName);
uploadPartRequest.setObjectKey(objectKey);
uploadPartRequest.setUploadId(uploadId);
uploadPartRequest.setFile(largeFile);
uploadPartRequest.setPartSize(currPartSize);
uploadPartRequest.setOffset(offset);
uploadPartRequest.setPartNumber(partNumber);
try {
UploadPartResult uploadPartResult = wosClient.uploadPart(uploadPartRequest);
System.out.println("Part#" + partNumber + " done\n");
partEtags.add(new PartEtag(uploadPartResult.getEtag(), uploadPartResult.getPartNumber()));
} catch (WosException e) {
e.printStackTrace();
}
});
}
executorService.shutdown();
while (!executorService.isTerminated()) {
executorService.awaitTermination(5, TimeUnit.SECONDS);
}
// 병합
CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, objectKey, uploadId, partEtags);
wosClient.completeMultipartUpload(completeMultipartUploadRequest);
참고: 멀티파트 업로드에서는 각 파트마다 UploadPartRequest.setOffset, setPartSize로 오프셋/길이 지정이 필요합니다.
진행 중인 멀티파트 업로드 작업은 중단(취소)할 수 있습니다. 중단 이후 해당 Upload ID는 무효화되고, 업로드된 파트 데이터도 삭제됩니다.
저장 공간을 절약하려면 실패하거나 진행 중인 멀티파트 작업을 직접 중단 처리할 수 있습니다.
AbortMultipartUploadRequest request = new AbortMultipartUploadRequest("bucketname", "objectname", uploadId);
wosClient.abortMultipartUpload(request);
WosClient.listParts로 특정 멀티파트 업로드 작업에 대하여 업로드된 파트들의 정보(번호, 크기, ETag 등 전체)를 조회할 수 있습니다.
ListPartsRequest request = new ListPartsRequest("bucketname", "objectname");
request.setUploadId(uploadId);
ListPartsResult result = wosClient.listParts(request);
for (Multipart part : result.getMultipartList()) {
System.out.println("\t" + part.getPartNumber()); // 파트 번호
System.out.println("\t" + part.getSize()); // 파트 크기
System.out.println("\t" + part.getEtag()); // 파트 ETag
System.out.println("\t" + part.getLastModified()); // 업로드 일시
}
참고:
- 한 번에 최대 1,000개 파트가 반환됩니다. 1,000개 초과 시
ListPartsResult.isTruncated()가 true를 반환하며,getNextPartNumberMarker()로 페이징 처리해야 합니다.- 1,000개가 넘는 파트는 반복 호출로 모두 조회할 수 있습니다.
do {
result = wosClient.listParts(request);
for(Multipart part : result.getMultipartList()){
// 파트 정보 출력
}
request.setPartNumberMarker(Integer.parseInt(result.getNextPartNumberMarker()));
} while (result.isTruncated());
WosClient.listMultipartUploads를 사용하면 현재 진행 중인 모든 멀티파트 업로드 작업(Upload ID 리스트 포함)을 조회할 수 있습니다.
ListMultipartUploadsRequest request = new ListMultipartUploadsRequest("bucketname");
MultipartUploadListing result = wosClient.listMultipartUploads(request);
for (MultipartUpload upload : result.getMultipartTaskList()) {
System.out.println("\t" + upload.getUploadId());
System.out.println("\t" + upload.getObjectKey());
System.out.println("\t" + upload.getInitiatedDate());
}
참고:
- 한 번에 최대 1,000개 작업이 반환됩니다. 페이징 시 isTruncated(), getNextKeyMarker(), getNextUploadIdMarker() 사용
페이징 처리 예시:
do {
result = wosClient.listMultipartUploads(request);
for (MultipartUpload upload : result.getMultipartTaskList()) {
// 업로드 정보 출력
}
request.setKeyMarker(result.getNextKeyMarker());
request.setUploadIdMarker(result.getNextUploadIdMarker());
} while (result.isTruncated());
폼 기반 업로드는 HTML 양식(Form)을 사용하여 오브젝트를 업로드하는 방식입니다. 업로드 가능한 최대 오브젝트 크기는 5GB입니다.
WosClient.createPostSignature를 통해 폼 업로드에 필요한 파라미터를 생성할 수 있습니다. 예시는 PostObjectSample을 참고하세요.
진행 절차:
WosClient.createPostSignature를 호출해 인증 정보 생성WosClient.createPostSignature로 생성되는 파라미터:
policy (form의 policy 필드)signature (form의 signature 필드)폼 파라미터 생성 예시:
PostSignatureRequest request = new PostSignatureRequest();
Map<String, Object> formParams = new HashMap<String, Object>();
formParams.put("x-wos-acl", "public-read"); // ACL 설정
formParams.put("content-type", "text/plain"); // MIME 타입 설정
request.setFormParams(formParams);
request.setExpires(3600); // 유효기간(초)
PostSignatureResponse response = wosClient.createPostSignature(request);
formParams.put("key", objectKey);
formParams.put("policy", response.getPolicy());
formParams.put("accesskeyid", ak);
formParams.put("x-wos-credential", response.getCredential());
formParams.put("x-wos-algorithm", response.getAlgorithm());
formParams.put("bucket", bucketName);
formParams.put("x-wos-date", response.getDate());
formParams.put("x-wos-signature", response.getSignature());
System.out.println("\t" + response.getPolicy());
System.out.println("\t" + response.getSignature());
HTML Form 예시:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<form action="http://bucketname.your-endpoint/" method="post" enctype="multipart/form-data">
Object key
<input type="text" name="key" value="objectname" />
<p>
ACL
<input type="text" name="x-wos-acl" value="public-read" />
<p>
Content-Type
<input type="text" name="content-type" value="text/plain" />
<p>
<input type="hidden" name="policy" value="*** Provide your policy ***" />
<input type="hidden" name="AccessKeyId" value="*** Provide your access key ***"/>
<input type="hidden" name="signature" value="*** Provide your signature ***"/>
<input name="file" type="file" />
<input name="submit" value="Upload" type="submit" />
</form>
</body>
</html>
참고:
- HTML 폼의
policy및signature값은WosClient.createPostSignature반환값으로 채우면 됩니다.- 샘플 HTML 폼(PostDemo)을 다운로드하여 데모로 사용할 수 있습니다.