Object Storage Service (OSS) は、オブジェクトのアップロード、ダウンロード、コピー時にデータ整合性を確保するため、データ検証用に MD5 と 64 ビット巡回冗長検査 (CRC-64) を提供します。
注意事項
このトピックでは、中国 (杭州) リージョンのパブリックエンドポイントを使用します。 同じリージョン内の他の Alibaba Cloud サービスから OSS にアクセスするには、内部エンドポイントを使用します。 サポートされているリージョンとエンドポイントの詳細については、リージョンとエンドポイントをご参照ください。
このトピックでは、アクセス認証情報は環境変数から取得します。 アクセス認証情報の設定方法の詳細については、アクセス認証情報の設定をご参照ください。
このトピックでは、OSS エンドポイントを使用して OSSClient インスタンスを作成します。 カスタムドメイン名または Security Token Service (STS) を使用して OSSClient インスタンスを作成する場合は、一般的なシナリオの設定例をご参照ください。
MD5 検証
ファイルをアップロードする際、Content-MD5 ヘッダーを設定してデータ整合性を確保できます。 OSS は受信したコンテンツの MD5 ハッシュを計算します。 OSS が計算した MD5 ハッシュが、指定された MD5 ハッシュと一致しない場合、OSS は InvalidDigest エラーを返します。 このエラーが発生した場合は、ファイルを再度アップロードする必要があります。
MD5 検証は、マルチパートアップロードでもサポートされています。 マルチパートアップロードの場合、MD5 検証は各パートに対して実行されます。 これを行うには、UploadPartRequest の setMd5Digest メソッドを呼び出して、クライアントで計算されたパートの MD5 ハッシュを設定します。
putObject、getObject、appendObject、postObject、マルチパートアップロード、および uploadPart 操作で MD5 検証がサポートされています。
ファイルをアップロードする際に MD5 検証を実行する:
import com.aliyun.oss.*; import com.aliyun.oss.common.auth.*; import com.aliyun.oss.common.comm.SignVersion; import com.aliyun.oss.common.utils.BinaryUtil; import com.aliyun.oss.model.ObjectMetadata; import java.io.ByteArrayInputStream; public class Demo { public static void main(String[] args) throws Throwable { // この例では、中国 (杭州) リージョンのエンドポイントを使用します。 実際の値に置き換えてください。 String endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // 環境変数からアクセス認証情報を取得します。 このサンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。 EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // バケット名を指定します。 例: examplebucket。 String bucketName = "examplebucket"; // オブジェクトの完全なパスを指定します。 完全なパスにバケット名を含めることはできません。 String objectName = "exampledir/object"; // バケットが配置されているリージョンを指定します。 この例では、中国 (杭州) リージョンのバケットに 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 { // 文字列をアップロードします。 String content = "Hello OSS"; ObjectMetadata meta = new ObjectMetadata(); // MD5 検証を設定します。 String md5 = BinaryUtil.toBase64String(BinaryUtil.calculateMd5(content.getBytes())); meta.setContentMD5(md5); ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content.getBytes()), meta); } 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(); } } } }マルチパートアップロードで MD5 検証を実行する:
import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import com.aliyun.oss.ClientBuilderConfiguration; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.common.auth.CredentialsProviderFactory; import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider; import com.aliyun.oss.common.comm.SignVersion; import com.aliyun.oss.common.utils.BinaryUtil; import com.aliyun.oss.model.CompleteMultipartUploadRequest; import com.aliyun.oss.model.CompleteMultipartUploadResult; import com.aliyun.oss.model.InitiateMultipartUploadRequest; import com.aliyun.oss.model.InitiateMultipartUploadResult; import com.aliyun.oss.model.PartETag; import com.aliyun.oss.model.UploadPartRequest; import com.aliyun.oss.model.UploadPartResult; public class Demo { public static void main(String[] args) throws Exception { // この例では、中国 (杭州) リージョンのエンドポイントを使用します。 実際の値に置き換えてください。 String endpoint = "http://oss-cn-hangzhou.aliyuncs.com"; // 環境変数からアクセス認証情報を取得します。 このサンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。 EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // バケット名を指定します。 例: examplebucket。 String bucketName = "examplebucket"; // オブジェクトの完全なパスを指定します。 完全なパスにバケット名を含めることはできません。 String objectName = "exampledir/object"; // アップロードするローカルファイルのパス。 String localFile = "D:\\localpath\\examplefile.txt"; // バケットが配置されているリージョンを指定します。 この例では、中国 (杭州) リージョンのバケットに 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(); // InitiateMultipartUploadRequest オブジェクトを作成します。 InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName); // マルチパートアップロードを初期化する際にストレージクラスを設定するには、次のサンプルコードをご参照ください。 // ObjectMetadata metadata = new ObjectMetadata(); // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString()); // request.setObjectMetadata(metadata); // マルチパートアップロードを初期化します。 InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request); // アップロード ID が返されます。 アップロード ID は、マルチパートアップロードイベントを一意に識別します。 アップロード ID を使用して、マルチパートアップロードのキャンセルやパートのクエリなどの操作を実行できます。 String uploadId = upresult.getUploadId(); // partETags は PartETag オブジェクトのコレクションです。 PartETag オブジェクトは、パートの ETag とパート番号で構成されます。 List<PartETag> partETags = new ArrayList<PartETag>(); // パート数を計算します。 final long partSize = 1 * 1024 * 1024L; // 1 MB final File sampleFile = new File(localFile); long fileLength = sampleFile.length(); int partCount = (int) (fileLength / partSize); if (fileLength % partSize != 0) { partCount++; } // パートを走査してアップロードします。 for (int i = 0; i < partCount; i++) { long startPos = i * partSize; long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize; InputStream instream = new FileInputStream(sampleFile); InputStream instream1 = new FileInputStream(sampleFile); // アップロード済みのパートをスキップします。 instream.skip(startPos); instream1.skip(startPos); String md5; if(i==partCount-1){ // 注意: 最後のパートでは、データはパートのサイズではなく、ファイルの終わりまで読み取られます。 md5 = md5(instream1,fileLength - startPos); }else{ md5 = md5(instream1,partSize); } // instream1.skip(n) UploadPartRequest uploadPartRequest = new UploadPartRequest(); uploadPartRequest.setBucketName(bucketName); uploadPartRequest.setKey(objectName); uploadPartRequest.setUploadId(uploadId); uploadPartRequest.setInputStream(instream); uploadPartRequest.setMd5Digest(md5); // パートサイズを設定します。 最後のパートを除き、パートの最小サイズは 100 KB です。 uploadPartRequest.setPartSize(curPartSize); // パート番号を設定します。 アップロードされる各パートには、1 から 10,000 までの範囲のパート番号があります。 パート番号がこの範囲にない場合、OSS は InvalidArgument エラーを返します。 uploadPartRequest.setPartNumber( i + 1); // パートを順番にアップロードする必要はありません。 異なるクライアントからパートをアップロードすることもできます。 OSS は、パート番号に基づいてパートを完全なファイルに結合します。 UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest); // System.out.println("server md5" +uploadPartResult.getETag()); // 各パートがアップロードされると、OSS は PartETag を含む結果を返します。 PartETag は partETags に格納されます。 partETags.add(uploadPartResult.getPartETag()); } // CompleteMultipartUploadRequest オブジェクトを作成します。 // マルチパートアップロードを完了する際には、すべての有効な partETags を提供する必要があります。 OSS は送信された partETags を受信した後、各パートの有効性を検証します。 すべてのパートが検証された後、OSS はそれらを完全なファイルに結合します。 CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags); // マルチパートアップロードを完了する際にファイルのアクセス権限を設定するには、次のサンプルコードをご参照ください。 // completeMultipartUploadRequest.setObjectACL(CannedAccessControlList.PublicRead); // アップロードを完了します。 CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest); // OSSClient をシャットダウンします。 ossClient.shutdown(); } public static String md5(InputStream in , long length1) throws Exception{ byte[] bytes = new byte[(int) length1]; long length_tmp = length1; int readSize = in.read(bytes, (int) 0, (int) length_tmp); return BinaryUtil.toBase64String(BinaryUtil.calculateMd5(bytes)); } }
CRC-64 検証
デフォルトでは、データ整合性を確保するために、ファイルのアップロード、ダウンロード、およびコピー操作で CRC-64 データ検証が有効になっています。
putObject、getObject、appendObject、および uploadPart 操作は CRC-64 検証をサポートしています。 デフォルトでは、アップロードに対して CRC-64 検証が有効になっています。 クライアントで計算された CRC 値がサーバーから返された CRC 値と異なる場合、InconsistentException エラーがスローされます。
範囲ダウンロードは CRC-64 検証をサポートしていません。
CRC-64 検証は CPU リソースを消費するため、アップロードおよびダウンロードの速度に影響を与える可能性があります。
ファイルをダウンロードする際に CRC-64 検証を実行する:
次のコードは、ファイルをダウンロードする際に CRC-64 を使用してデータ整合性を検証する方法を示しています:
import com.aliyun.oss.*; import com.aliyun.oss.common.auth.*; import com.aliyun.oss.common.comm.SignVersion; import com.aliyun.oss.common.utils.IOUtils; import com.aliyun.oss.internal.OSSHeaders; import com.aliyun.oss.internal.OSSUtils; import com.aliyun.oss.model.GetObjectRequest; import com.aliyun.oss.model.OSSObject; import java.io.BufferedReader; import java.io.InputStreamReader; public class Demo { public static void main(String[] args) throws Throwable { // この例では、中国 (杭州) リージョンのエンドポイントを使用します。 実際の値に置き換えてください。 String endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // 環境変数からアクセス認証情報を取得します。 このサンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。 EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // バケット名を指定します。 例: examplebucket。 String bucketName = "examplebucket"; // オブジェクトの完全なパスを指定します。 完全なパスにバケット名を含めることはできません。 String objectName = "exampledir/object"; // バケットが配置されているリージョンを指定します。 この例では、中国 (杭州) リージョンのバケットに 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 { // ストリーミングダウンロードを実行します。 GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, objectName); OSSObject ossObject = ossClient.getObject(bucketName, objectName); // ファイルの内容を読み取ります。 clientCrc は、ファイルの内容を読み取った後にのみ取得できます。 System.out.println("Object content:"); BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent())); while (true) { String line = reader.readLine(); if (line == null) break; System.out.println("\n" + line); } // データの読み取り後、ストリームを閉じる必要があります。 そうしないと、接続リークが発生する可能性があります。 これにより、プログラムが利用可能な接続を使い果たし、動作を停止する原因となります。 reader.close(); // クライアントで CRC 検証が有効になっているかどうかを確認します。 デフォルトでは有効です。 Boolean isCrcCheckEnabled = ((OSSClient)ossClient).getClientConfiguration().isCrcCheckEnabled(); // リクエストが範囲ダウンロードであるかどうかを確認します。 範囲ダウンロードは CRC 検証をサポートしていません。 Boolean isRangGetRequest = getObjectRequest.getHeaders().get(OSSHeaders.RANGE) != null; // CRC を検証します。 clientCRC は、ファイルの内容を読み取った後にのみ取得できます。 if (isCrcCheckEnabled && !isRangGetRequest) { Long clientCRC = IOUtils.getCRCValue(ossObject.getObjectContent()); OSSUtils.checkChecksum(clientCRC, ossObject.getServerCRC(), ossObject.getRequestId()); } } 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(); } } } }追加アップロードで CRC-64 検証を実行する:
次のコードは、追加アップロードでデータ整合性を検証するために CRC-64 を使用する方法を示しています:
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.ByteArrayInputStream; 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"; // オブジェクトの完全なパス (例: exampleobject.txt) を指定します。 完全なパスにバケット名を含めることはできません。 String objectName = "exampleobject.txt"; // 最初の追加操作のコンテンツを指定します。 例: Hello。 String firstAppendContent = "Hello"; // 2 番目の追加操作のコンテンツを指定します。 例: World。 String secondAppendContent = "World"; // バケットが配置されているリージョンを指定します。 この例では、中国 (杭州) リージョンのバケットに 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 { // 最初の追加操作を実行します。 AppendObjectRequest appendObjectRequest = new AppendObjectRequest(bucketName, objectName, new ByteArrayInputStream(firstAppendContent.getBytes())); appendObjectRequest.setPosition(0L); // CRC を初期化します。 初期化後、SDK はデフォルトでアップロード結果に対して CRC 検証を実行します。 appendObjectRequest.setInitCRC(0L); AppendObjectResult appendObjectResult = ossClient.appendObject(appendObjectRequest); // 2 番目の追加操作を実行します。 appendObjectRequest = new AppendObjectRequest(bucketName, objectName, new ByteArrayInputStream(secondAppendContent.getBytes())); appendObjectRequest.setPosition(appendObjectResult.getNextPosition()); // 初期 CRC をアップロード済みデータの CRC に設定します。 初期化後、SDK はデフォルトでアップロード結果に対して CRC 検証を実行します。 appendObjectRequest.setInitCRC(appendObjectResult.getClientCRC()); ossClient.appendObject(appendObjectRequest); } 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(); } } } }
関連ドキュメント
データ検証の完全なサンプルコードについては、GitHub の例をご参照ください。