全部產品
Search
文件中心

Object Storage Service:Java上傳檔案

更新時間:Jun 19, 2024

本文介紹如何在受版本控制的儲存空間(Bucket)中上傳檔案(Object)。

注意事項

  • 本文以華東1(杭州)外網Endpoint為例。如果您希望通過與OSS同地區的其他阿里雲產品訪問OSS,請使用內網Endpoint。關於OSS支援的Region與Endpoint的對應關係,請參見訪問網域名稱和資料中心

  • 本文以從環境變數讀取存取憑證為例。如何配置訪問憑證,請參見Java配置訪問憑證

  • 本文以OSS網域名稱建立OSSClient為例。如果您希望通過自訂網域名、STS等方式建立OSSClient,請參見建立OSSClient

  • 要上傳檔案,您必須有oss:PutObject許可權。具體操作,請參見為RAM使用者授權自訂的權限原則

簡單上傳

在已開啟版本控制的Bucket中,OSS會為新添加的Object自動產生唯一的VersionId,並在響應header中通過x-oss-version-id形式返回。在暫停了版本控制的Bucket中,新添加的Object的VersionId為“null”,上傳同名Object,後一次會覆蓋前一次上傳的檔案內容。OSS保證同一個Object只會有一個版本的ID為“null”。

以下代碼用於簡單上傳:

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import java.io.ByteArrayInputStream;

public class Demo {
    public static void main(String[] args) throws Exception {
        // Endpoint以華東1(杭州)為例,其它Region請按實際情況填寫。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填寫Bucket名稱,例如examplebucket。
        String bucketName = "examplebucket";
        // 填寫Object的完整路徑。Object完整路徑中不能包含Bucket名稱。
        String objectName = "exampledir/object";

        // 建立OSSClient執行個體。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            // 以上傳字串為例。
            String content = "Hello OSS";
            PutObjectResult result = ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content.getBytes()));
            // 查看此次上傳Object的VersionId。
            System.out.println("result.versionid: " + result.getVersionId());
        } 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();
            }
        }
    }
}

追加上傳

在受版本控制的Bucket中,僅支援對於目前的版本為Appendable類型的Object執行追加(AppendObject)操作,不支援對於歷史版本為Appendable類型的Object執行AppendObject操作。

說明
  • 對目前的版本為Appendable類型的Object執行AppendObject操作時,OSS不會為該Appendable類型的Object產生歷史版本。

  • 對目前的版本為Appendable類型的Object執行PutObject或DeleteObject操作時,OSS會將該Appendable類型的Object保留為歷史版本,且該Object不允許繼續追加。

  • 不支援對目前的版本為非Appendable類型的Object(包括 Normal Object、Delete Marker等)執行AppendObject 操作。

以下代碼用於追加上傳:

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import java.io.ByteArrayInputStream;

public class Demo {
    public static void main(String[] args) throws Exception {
        // Endpoint以華東1(杭州)為例,其它Region請按實際情況填寫。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填寫Bucket名稱,例如examplebucket。
        String bucketName = "examplebucket";
        // 填寫Object的完整路徑。Object完整路徑中不能包含Bucket名稱。
        String objectName = "exampledir/object";
        String content1 = "Hello OSS A \n";
        String content2 = "Hello OSS B \n";
        String content3 = "Hello OSS C \n";

        // 建立OSSClient執行個體。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            ObjectMetadata meta = new ObjectMetadata();
            // 指定上傳的內容類型。
            meta.setContentType("text/plain");

            // 通過AppendObjectRequest設定多個參數。
            AppendObjectRequest appendObjectRequest = new AppendObjectRequest(bucketName, objectName, new ByteArrayInputStream(content1.getBytes()),meta);

            // 通過AppendObjectRequest設定單個參數。
            // 設定儲存空間名稱。
            //appendObjectRequest.setBucketName("<yourBucketName>");
            // 設定檔案名稱。
            //appendObjectRequest.setKey("<yourObjectName>");
            // 設定待追加的內容。有兩種可選類型:InputStream類型和File類型。這裡為InputStream類型。
            //appendObjectRequest.setInputStream(new ByteArrayInputStream(content1.getBytes()));
            // 設定待追加的內容。有兩種可選類型:InputStream類型和File類型。這裡為File類型。
            //appendObjectRequest.setFile(new File("<yourLocalFile>"));
            // 指定檔案的中繼資料,第一次追加時有效。
            //appendObjectRequest.setMetadata(meta);

            // 第一次追加。
            // 設定檔案的追加位置。
            appendObjectRequest.setPosition(0L);
            AppendObjectResult appendObjectResult = ossClient.appendObject(appendObjectRequest);
            // 檔案的64位CRC值。此值根據ECMA-182標準計算得出。
            System.out.println(appendObjectResult.getObjectCRC());

            // 第二次追加。
            // nextPosition指明下一次請求中應當提供的Position,即檔案當前的長度。
            appendObjectRequest.setPosition(appendObjectResult.getNextPosition());
            appendObjectRequest.setInputStream(new ByteArrayInputStream(content2.getBytes()));
            appendObjectResult = ossClient.appendObject(appendObjectRequest);

            // 第三次追加。
            appendObjectRequest.setPosition(appendObjectResult.getNextPosition());
            appendObjectRequest.setInputStream(new ByteArrayInputStream(content3.getBytes()));
            appendObjectResult = 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();
            }
        }
    }
}

分區上傳

在受版本控制的Bucket中,調用CompleteMultipartUpload介面來完成整個檔案的分區上傳,OSS會為整個檔案產生唯一的版本ID,並在響應header中以x-oss-version-id的形式返回。

以下代碼用於分區上傳:

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class Demo {
    public static void main(String[] args) throws Exception {
        // Endpoint以華東1(杭州)為例,其它Region請按實際情況填寫。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填寫Bucket名稱,例如examplebucket。
        String bucketName = "examplebucket";
        // 填寫Object的完整路徑。Object完整路徑中不能包含Bucket名稱。
        String objectName = "exampledir/object";
        String localFile = "D://example.txt";

        // 建立OSSClient執行個體。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            /* 步驟1:初始化一個分區上傳事件。
             */
            InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName);
            InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
            // 返回uploadId,它是分區上傳事件的唯一標識,您可以根據此uploadId來發起相關的操作,如取消分區上傳、查詢分區上傳等。
            String uploadId = upresult.getUploadId();

            /* 步驟2:上傳分區。
             */
            // partETags是PartETag的集合。PartETag由分區的ETag和分區號組成。
            List<PartETag> partETags =  new ArrayList<PartETag>();
            // 計算檔案有多少個分區。
            final long partSize = 1 * 1024 * 1024L;   // 1MB
            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);
                // 跳過已經上傳的分區。
                instream.skip(startPos);
                UploadPartRequest uploadPartRequest = new UploadPartRequest();
                uploadPartRequest.setBucketName(bucketName);
                uploadPartRequest.setKey(objectName);
                uploadPartRequest.setUploadId(uploadId);
                uploadPartRequest.setInputStream(instream);
                // 設定分區大小。除了最後一個分區沒有大小限制,其他的分區最小為100 KB。
                uploadPartRequest.setPartSize(curPartSize);
                // 設定分區號。每一個上傳的分區都有一個分區號,取值範圍是1~10000,如果超出這個範圍,OSS將返回InvalidArgument的錯誤碼。
                uploadPartRequest.setPartNumber( i + 1);
                // 每個分區不需要按順序上傳,甚至可以在不同用戶端上傳,OSS會按照分區號排序組成完整的檔案。
                UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
                // 每次上傳分區之後,OSS的返回結果會包含一個PartETag。PartETag將被儲存到partETags中。
                partETags.add(uploadPartResult.getPartETag());
            }

            /* 步驟3:完成分區上傳。
             */
            // 在執行該操作時,需要提供所有有效partETags。OSS收到提交的partETags後,會逐一驗證每個分區的有效性。當所有的資料分區驗證通過後,OSS將把這些分區組合成一個完整的檔案。
            CompleteMultipartUploadRequest completeMultipartUploadRequest =
                    new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);

            CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
            // 查看上傳檔案的VersionId。
            System.out.println("restore object versionid: " + completeMultipartUploadResult.getVersionId());

        } 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();
            }
        }
    }
}

相關文檔