このトピックでは、Object Storage Service (OSS) バケットからオブジェクトをローカルファイルにダウンロードする方法について説明します。
注意事項
このトピックでは、中国 (杭州) リージョンのパブリックエンドポイントを使用します。同じリージョン内の他の Alibaba Cloud サービスから OSS にアクセスするには、内部エンドポイントを使用します。サポートされているリージョンとエンドポイントの詳細については、「リージョンとエンドポイント」をご参照ください。
このトピックでは、アクセス認証情報は環境変数から取得します。アクセス認証情報の設定方法の詳細については、「アクセス認証情報の設定」をご参照ください。
このトピックでは、OSS エンドポイントを使用して OSSClient インスタンスを作成します。カスタムドメイン名またはセキュリティトークンサービス (STS) を使用して OSSClient インスタンスを作成する場合は、「一般的なシナリオの設定例」をご参照ください。
権限
デフォルトでは、Alibaba Cloud アカウントは完全な権限を持っています。Alibaba Cloud アカウントに属する RAM ユーザーまたは RAM ロールは、デフォルトではいかなる権限も持っていません。Alibaba Cloud アカウントまたはアカウント管理者は、RAM ポリシーまたはバケットポリシーを通じて操作権限を付与する必要があります。
API | アクション | 定義 |
GetObject |
| オブジェクトをダウンロードします。 |
| オブジェクトをダウンロードする際に、versionId を通じてオブジェクトのバージョンを指定する場合、この権限が必要です。 | |
| オブジェクトをダウンロードする際に、オブジェクトのメタデータに X-Oss-Server-Side-Encryption: KMS が含まれている場合、この権限が必要です。 |
単一オブジェクトのローカルファイルへのダウンロード
次のコードは、examplebucket バケットの testfolder フォルダから exampleobject.txt オブジェクトをダウンロードし、ローカルパス D:\localpath に examplefile.txt として保存する方法を示しています。
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.GetObjectRequest;
import java.io.File;
public class Demo {
public static void main(String[] args) throws Exception {
// エンドポイントを設定します。例として中国 (杭州) リージョンを使用します。実際のエンドポイントに変更してください。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// バケット名を指定します。例:examplebucket
String bucketName = "examplebucket";
// オブジェクトの完全なパスを指定します。バケット名は含めないでください。例:testfolder/exampleobject.txt
String objectName = "testfolder/exampleobject.txt";
// オブジェクトをダウンロードする完全なパスを指定します。
String pathName = "D:\\localpath\\examplefile.txt";
// バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合、Region を cn-hangzhou に設定します。
String region = "cn-hangzhou";
// OSSClient インスタンスを作成します。
// OSSClient インスタンスが不要になったら、shutdown メソッドを呼び出してリソースを解放します。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
// オブジェクトをローカルファイルにダウンロードし、指定されたローカルパスに保存します。指定されたローカルファイルが存在する場合は上書きされ、存在しない場合は作成されます。
// ローカルパスを指定しない場合、ダウンロードされたオブジェクトはデフォルトでサンプルプログラムのプロジェクトに対応するローカルパスに保存されます。
ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File(pathName));
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
} 複数オブジェクトのローカルパスへのダウンロード
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.*;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class BatchDownloadObject {
public static void main(String[] args) throws Exception {
// エンドポイントを設定します。例として中国 (杭州) リージョンを使用します。実際のエンドポイントに変更してください。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// バケット名を指定します。例:examplebucket
String bucketName = "examplebuckett";
// ダウンロードするフォルダのプレフィックスを指定します。例:"images/"。バケット全体をダウンロードする場合は、空のままにします。
String folderPrefix = "";
// ローカルのダウンロードフォルダを指定します。
String localDownloadPath = "./batch_downloads/";
// バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合、Region を cn-hangzhou に設定します。
String region = "cn-hangzhou";
// OSSClient インスタンスを作成します。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
// ローカルのダウンロードフォルダが存在することを確認します。
createDirectoryIfNotExists(localDownloadPath);
// オブジェクトをバッチでダウンロードします。
batchDownloadObjects(ossClient, bucketName, folderPrefix, localDownloadPath);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
/**
* OSS からローカルパスにオブジェクトをバッチでダウンロードします。
* @param ossClient OSS クライアント。
* @param bucketName バケット名。
* @param folderPrefix フォルダのプレフィックス。
* @param localDownloadPath ローカルのダウンロードパス。
*/
public static void batchDownloadObjects(OSS ossClient, String bucketName, String folderPrefix, String localDownloadPath) {
String nextMarker = null;
ObjectListing objectListing;
int downloadCount = 0;
long totalSize = 0;
int failedCount = 0;
System.out.println("Starting batch download...");
System.out.println("Source path: " + bucketName + "/" + folderPrefix);
System.out.println("Local path: " + localDownloadPath);
System.out.println("----------------------------------------");
long startTime = System.currentTimeMillis();
do {
// オブジェクトをリストアップします。
ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName)
.withPrefix(folderPrefix)
.withMarker(nextMarker)
.withMaxKeys(1000); // 一度に最大 1,000 個のオブジェクトをリストアップします。
objectListing = ossClient.listObjects(listObjectsRequest);
List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
for (OSSObjectSummary s : sums) {
// フォルダ (末尾が / のオブジェクト) をスキップします。
if (s.getKey().endsWith("/")) {
continue;
}
try {
// ローカルファイルパスを構築します。
String localFilePath = constructLocalFilePath(localDownloadPath, s.getKey(), folderPrefix);
// ローカルファイルの親フォルダを作成します。
File localFile = new File(localFilePath);
createDirectoryIfNotExists(localFile.getParent());
// 繰り返しダウンロードを避けるためにファイルが存在するかどうかを確認します。
if (localFile.exists() && localFile.length() == s.getSize()) {
System.out.println("File already exists. Skip download: " + s.getKey());
downloadCount++;
totalSize += s.getSize();
continue;
}
// オブジェクトをダウンロードします。
System.out.println("Downloading: " + s.getKey() + " -> " + localFilePath);
// ダウンロード中のファイル破損を防ぐために一時ファイルを使用します。
File tempFile = new File(localFilePath + ".tmp");
try {
ossClient.getObject(new GetObjectRequest(bucketName, s.getKey()), tempFile);
// ダウンロードが完了したら、一時ファイルを最終的なファイル名にリネームします。
if (tempFile.renameTo(localFile)) {
downloadCount++;
totalSize += s.getSize();
System.out.println("Download complete: " + s.getKey() + " (Size: " + formatFileSize(s.getSize()) + ")");
} else {
throw new IOException("Failed to rename the temporary file: " + tempFile.getPath() + " -> " + localFile.getPath());
}
} finally {
// 一時ファイルをクリーンアップします。
if (tempFile.exists()) {
tempFile.delete();
}
}
} catch (Exception e) {
failedCount++;
System.err.println("Failed to download the file: " + s.getKey() + ", Error: " + e.getMessage());
// デバッグのために詳細なエラーメッセージを記録します。
if (e instanceof OSSException) {
OSSException oe = (OSSException) e;
System.err.println("OSS Error Code: " + oe.getErrorCode() + ", Request ID: " + oe.getRequestId());
}
}
}
nextMarker = objectListing.getNextMarker();
} while (objectListing.isTruncated());
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
System.out.println("----------------------------------------");
System.out.println("Batch download complete!");
System.out.println("Total number of files downloaded: " + downloadCount);
System.out.println("Number of failed downloads: " + failedCount);
System.out.println("Total download size: " + formatFileSize(totalSize));
System.out.println("Total time elapsed: " + formatDuration(duration));
System.out.println("Average download speed: " + formatSpeed(totalSize, duration));
}
/**
* ローカルファイルパスを構築します。
* @param localDownloadPath ローカルダウンロードのルートディレクトリ。
* @param objectKey OSS オブジェクトキー。
* @param folderPrefix フォルダのプレフィックス。
* @return ローカルファイルの完全なパス。
*/
private static String constructLocalFilePath(String localDownloadPath, String objectKey, String folderPrefix) {
// プレフィックスを削除して相対パス構造を維持します。
String relativePath = objectKey;
if (folderPrefix != null && !folderPrefix.isEmpty() && objectKey.startsWith(folderPrefix)) {
relativePath = objectKey.substring(folderPrefix.length());
}
// パス区切り文字が正しいことを確認します。
String normalizedPath = localDownloadPath.endsWith(File.separator) ?
localDownloadPath : localDownloadPath + File.separator;
return normalizedPath + relativePath.replace("/", File.separator);
}
/**
* フォルダが存在しない場合に作成します。
* @param dirPath フォルダパス。
*/
private static void createDirectoryIfNotExists(String dirPath) {
if (dirPath == null || dirPath.isEmpty()) {
return;
}
try {
File dir = new File(dirPath);
if (!dir.exists()) {
boolean created = dir.mkdirs();
if (created) {
System.out.println("Creating folder: " + dirPath);
} else if (!dir.exists()) {
throw new IOException("Failed to create folder: " + dirPath);
}
}
} catch (Exception e) {
System.err.println("Failed to create folder: " + dirPath + ", Error: " + e.getMessage());
throw new RuntimeException("Failed to create folder", e);
}
}
/**
* ファイルサイズをフォーマットします。
* @param size バイト単位のファイルサイズ。
* @return フォーマットされたファイルサイズの文字列。
*/
private static String formatFileSize(long size) {
if (size < 1024) {
return size + " B";
} else if (size < 1024 * 1024) {
return String.format("%.2f KB", size / 1024.0);
} else if (size < 1024 * 1024 * 1024) {
return String.format("%.2f MB", size / (1024.0 * 1024.0));
} else {
return String.format("%.2f GB", size / (1024.0 * 1024.0 * 1024.0));
}
}
/**
* 期間をフォーマットします。
* @param duration ミリ秒単位の期間。
* @return フォーマットされた期間の文字列。
*/
private static String formatDuration(long duration) {
long seconds = duration / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
if (hours > 0) {
return String.format("%d h %d min %d s", hours, minutes % 60, seconds % 60);
} else if (minutes > 0) {
return String.format("%d min %d s", minutes, seconds % 60);
} else {
return String.format("%d s", seconds);
}
}
/**
* ダウンロード速度をフォーマットします。
* @param totalBytes 合計バイト数。
* @param durationMs ミリ秒単位の期間。
* @return フォーマットされた速度の文字列。
*/
private static String formatSpeed(long totalBytes, long durationMs) {
if (durationMs <= 0) {
return "N/A";
}
double bytesPerSecond = (double) totalBytes / (durationMs / 1000.0);
if (bytesPerSecond < 1024) {
return String.format("%.2f B/s", bytesPerSecond);
} else if (bytesPerSecond < 1024 * 1024) {
return String.format("%.2f KB/s", bytesPerSecond / 1024.0);
} else if (bytesPerSecond < 1024 * 1024 * 1024) {
return String.format("%.2f MB/s", bytesPerSecond / (1024.0 * 1024.0));
} else {
return String.format("%.2f GB/s", bytesPerSecond / (1024.0 * 1024.0 * 1024.0));
}
}
}
関連 API
プログラムに高度なカスタマイズ要件がある場合は、REST API リクエストを直接送信できます。REST API リクエストを直接送信するには、署名を計算するためのコードを手動で記述する必要があります。詳細については、「GetObject」をご参照ください。
関連ドキュメント
オブジェクトをローカルファイルにダウンロードするための完全なサンプルコードについては、GitHub をご参照ください。