Object操作

简介

在BOS中,用户操作的基本数据单元是Object,用户可以在一个或者多个Bucket中存储这些Object,Object由以下内容组成:

  • Key:Object的名字,用于唯一标识Bucket中的Object,用户可以通过Key来读取Object。

  • Metadata:是用户对该Object的描述,由一系列的Name-Value对组成。用户可以通过管理控制台或者SDK修改object的Metadata。

  • Data:Object中存储的数据。Object的值可以是任意序列的字节,其大小范围是从0到5TB。

Key

Key是Object的名字,用于唯一标识Bucket中的Object。上传文件到BOS上时,默认使用文件名作为Object的名字,Object的名字可以修改。Object的Key是长度不超过1024字节的UTF-8格式字符。

Bucket存储中没有目录层级结构,但是可以通过Object名称中的Prefix和分隔符模拟文件夹功能。

说明:字符@不建议用于Object的Key中。图片服务中@会作为命令的间隔符,如果Object名称中包含@字符,在做图片处理时,@后的字符串会被识别为命令,产生错误。

Metadata

BOS中Object的Metadata包含系统定义的Metadata和用户自定义的Metadata两种。

系统定义的Metadata

每个Object都有一组Metadata信息,Metadata用来标识Object的属性如日期、内容长度等信息,这些Metadata信息用于Object管理。

系统定义的Metadata也分为用户可修改和用户不可修改两种。其中如Object的固有属性如创建日期、内容长度、上次修改时间、MD5码等为不可修改的Metadata。如Content-Type、Cache-Control、storage-class等Metadata,用户在创建Object时或者根据需要可以修改这些Metadata的值。系统定义的Metadata的详细描述参见下表:

名称 类型 描述 是否可被用户修改
Cache-Control String 下载Object的Cache设置,常见的可取值为private、no-cache、max-age、must-revalidate。
Content-Disposition String 设置浏览器是否下载,可取值为inline、attachment; "filename=download.txt"。
Content-MD5 String RFC2616定义的HTTP请求内容的MD5摘要,可以通过携带该字段来验证保存在BOS侧的文件和用户预期的文件是否一致。
Content-Length Long Int 返回Object的数据大小。
Content-Type String Object的类型及编码方式。
Expires String 设置下载Object时的缓存失效时间。
ETag String Object的HTTP协议实体标签。
x-bce-storage-class String 标准存储返回STANDARD,低频存储返回STANDARD_IA, 冷存储返回COLD
x-bce-object-type string 标识Object是Appendable还是普通的,Appendale的Object可以追加写,普通的不能。

用户自定义的Metadata

为了便于用户对Object进行更多描述。BOS中规定所有以x-bce-meta-为前缀的参数,则视为用户自定义的Metadata,比如x-bce-meta-tag。一个Object可以有若干个用户自定义Metadata。这些自定义Metadata会在下载GetObject或者HeadObject的时候在HTTP头部中返回。

说明:PUT请求头的大小限制为8KB。在PUT请求标头中,用户定义的Metadata的大小限制为2KB。

上传Object

根据上传数据的大小,BOS提供以下选项:

  • 单个Object上传:借助PutObject接口,用户可以上传最大5GB的Object数据。
  • 分块上传Object:用户可以使用分块上传API来上传最大5TB的Object数据。

    用户可以在如下的应用场景内(但不仅限于此),使用MultipartUpload上传模式,如:

    • 需要支持断点上传。
    • 上传超过5GB大小的文件。
    • 网络条件较差,和BOS的服务器之间的连接经常断开。
    • 需要流式地上传文件。
    • 上传文件之前,无法确定上传文件的大小。

单个Object上传

BOS同时支持使用API与使用SDK进行单个Object上传,具体如下:

下面是使用Java SDK的代码示例:

public void PutObject(BosClient client, String bucketName, String objectKey){
    // 获取指定文件
    File file = new File("/path/to/file.zip");

    // 以文件形式上传Object
    PutObjectResponse putObjectFromFileResponse = client.putObject(bucketName, objectKey, file);

Object分块上传

Object的分块上传允许用户将整个Object分成单个块进行上传,若任意分块传输失败,均可以重新传输该分块而不会影响到其他的上传分块。当Object的所有块均完成上传之后,BOS将这些块汇总起来,创建Object并进行校验。建议用户在大数据的场景下使用分块上传。

根据我们的经验建议,如果您的网络环境较差,可选择对大于10Mb的Object进行分块上传;如果您网络环境较好,可对大于50Mb的Object进行分块上传。

使用分块上传具有如下优势:

  • 提高吞吐量:用户可以并行上传分块以提高吞吐量
  • 从网络问题中快速恢复:分块上传支持断点续传,可以将由网络错误而导致的上传产生的影响减至最低。
  • 不需要确认Object的大小:在分块上传的场景下,用户可以不用关心Object的大小以及大小可能带来的上传失败场景。

BOS同时支持使用API与使用SDK进行单个Object上传,具体如下:

下面是使用Java SDK的代码示例:

开始并完成分块上传

// 开始Multipart Upload
InitiateMultipartUploadRequest initiateMultipartUploadRequest =
        new InitiateMultipartUploadRequest(bucketName, objectKey);
InitiateMultipartUploadResponse initiateMultipartUploadResponse =
        client.initiateMultipartUpload(initiateMultipartUploadRequest);

// 打印UploadId
System.out.println("UploadId: " + initiateMultipartUploadResponse.getUploadId());

// 设置每块为 5MB
final long partSize = 1024 * 1024 * 5L;

File partFile = new File("/path/to/file.zip");

// 计算分块数目
int partCount = (int) (partFile.length() / partSize);
if (partFile.length() % partSize != 0){
    partCount++;
}

// 新建一个List保存每个分块上传后的ETag和PartNumber
List<PartETag> partETags = new ArrayList<PartETag>();

for(int i = 0; i < partCount; i++){
    // 获取文件流
    FileInputStream fis = new FileInputStream(partFile);

    // 跳到每个分块的开头
    long skipBytes = partSize * i;
    fis.skip(skipBytes);

    // 计算每个分块的大小
    long size = partSize < partFile.length() - skipBytes ?
            partSize : partFile.length() - skipBytes;

    // 创建UploadPartRequest,上传分块
    UploadPartRequest uploadPartRequest = new UploadPartRequest();
    uploadPartRequest.setBucketName(bucketName);
    uploadPartRequest.setKey(objectKey);
    uploadPartRequest.setUploadId(initiateMultipartUploadResponse.getUploadId());
    uploadPartRequest.setInputStream(fis);
    uploadPartRequest.setPartSize(size);
    uploadPartRequest.setPartNumber(i + 1);
    UploadPartResponse uploadPartResponse = client.uploadPart(uploadPartRequest);

    // 将返回的PartETag保存到List中。
    partETags.add(uploadPartResponse.getPartETag());

    // 关闭文件
    fis.close();
}

CompleteMultipartUploadRequest completeMultipartUploadRequest =
        new CompleteMultipartUploadRequest(bucketName, objectKey, initiateMultipartUploadResponse.getUploadId(), partETags);

// 完成分块上传
CompleteMultipartUploadResponse completeMultipartUploadResponse =
        client.completeMultipartUpload(completeMultipartUploadRequest);

// 打印Object的ETag
System.out.println(completeMultipartUploadResponse.getETag());

列出未完成的分块上传

ListMultipartUploadsRequest listMultipartUploadsRequest = 
    new ListMultipartUploadsRequest(bucketName);

// 获取Bucket内所有上传事件
ListMultipartUploadsResponse listing = client.listMultipartUploads(listMultipartUploadsRequest);

列出已完成的分块上传

ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, objectKey, uploadId);

// 获取上传的所有Part信息
ListPartsResponse partListing = client.listParts(listPartsRequest);

取消分块上传

AbortMultipartUploadRequest abortMultipartUploadRequest =
        new AbortMultipartUploadRequest(bucketName, objectKey, uploadId);

// 取消分块上传
client.abortMultipartUpload(abortMultipartUploadRequest);

查看Bucket中Object列表

用户可以从BOS中获取指定Bucket中的Objec信息列表,BOS同时支持使用API与使用SDK工具两种方式实现,具体如下:

下面是使用Java SDK的代码示例,可以简单的完成列出Object:

public void listObjects(BosClient client, String bucketName) {

    // 获取指定Bucket下的所有Object信息
    ListObjectsResponse listing = client.listObjects(bucketName);

    // 遍历所有Object
    for (BosObjectSummary objectSummary : listing.getContents()) {
        System.out.println("ObjectKey: " + objectSummary.getKey());
    }

获取Object

用户可以从BOS中直接获取Object的信息,也可以通过固定的方式获取Object的Meta信息。这部分操作需要用户对Object所在的Bucket具有读权限。

BOS同时支持使用API与使用SDK工具获取Object,具体如下:

下面是使用Java SDK的代码示例,可以简单的完成获取Object:

public void getObject(BosClient client, String bucketName, String objectKey)
    throws IOException {

    // 获取Object,返回结果为BosObject对象
    BosObject object = client.getObject(bucketName, objectKey);

    // 获取ObjectMeta
    ObjectMetadata meta = object.getObjectMetadata();

    // 获取Object的输入流
    InputStream objectContent = object.getObjectContent();

    // 处理Object
    ...

    // 关闭流
    objectContent.close();
}

拷贝Object

拷贝操作将创建已存储在BOS中的Object的副本。在单个Object操作中,用户可以创建最大5GB的Object副本。通过使用CopyObject操作,用户可以完成以下内容:

  • 创建指定Object的其他副本。

  • 通过拷贝Object并删除原始Object来进行对Object重命名。

  • 在不同的Bucket中移动Object。

BOS同时支持使用API与使用SDK进行Object拷贝,具体如下:

下面是使用Java SDK的代码示例:

public void copyObject(BosClient client, String srcBucketName, String srcKey, String destBucketName, String destKey) {

    // 拷贝Object
    CopyObjectResponse copyObjectResponse = client.copyObject(srcBucketName, srcKey, destBucketName, destKey);
}

删除Object

BOS同时支持使用API与使用SDK工具删除单个http请求中的一个Object,并且至少需要对此Object存在的Bucket具有写权限,具体如下:

下面是使用Java SDK的代码示例:

public void deleteObject(BosClient client, String bucketName, String objectKey) {

    // 删除Object
    client.deleteObject(bucketName, objectKey);
}

设置Object权限

为了保证BOS中某些内容对外发布时的保密或合规性要求,用户在设置Bucket权限的同时,也可针对Object的读操作,单独调整其权限,以达到如下三种效果:

  • Object与所属bucket权限保持一致;
  • Object权限为公共读权限;
  • Object权限为私有读权限,即仅有Object所在的Bucket的所有者可读。

当Object读操作权限与所属Bucket权限不一致时,以Object权限为准。

设置和删除ObjectAcl需要拥有Object的FULL_CONTROL权限。

基于以上规则,有如下示例:

  • 示例1:Bucket01为公共读权限,其中包含的Object02为私有权限,则其他访问者对Object02不可读也不可写;
  • 示例2:Bucket01为公共读写权限,其中包含的Object02为私有权限,则其他访问者对Object02不可读,但可写;
  • 示例3:Bucket01为私有权限,其中包含的Object02为公共读权限,则其他访问者对Object02可读,但不可写;
  • 示例4:Bucket01中包含Object02,且Object02的权限设置为“与所属Bucket权限保持一致”,则访问者对于Object的使用能力完全取决于Bucket01开放的权限。

目前也支持通过API进行上述操作: