所有文档

          对象存储 BOS

          文件管理

          上传文件

          在BOS中,用户操作的基本数据单元是Object。Object包含Key、Meta和Data。其中,Key是Object的名字;Meta是用户对该Object的描述,由一系列Name-Value对组成;Data是Object的数据。

          BOS Java SDK提供了丰富的文件上传接口,可以通过以下方式上传文件:

          • 简单上传
          • 追加上传
          • 分片上传
          • 断点续传上传

          简单上传

          BOS在简单上传的场景中,支持以指定文件形式、以数据流方式、以二进制串方式、以字符串方式执行Object上传,请参考如下代码,或简单上传Demo

          public void PutObject(BosClient client, String bucketName, String objectKey, byte[] byte1, String string1){
              // 获取指定文件
              File file = new File("/path/to/file.zip");
              // 获取数据流
              InputStream inputStream = new FileInputStream("/path/to/test.zip");
          	
              // 以文件形式上传Object
              PutObjectResponse putObjectFromFileResponse = client.putObject(bucketName, objectKey, file);
              // 以数据流形式上传Object
              PutObjectResponse putObjectResponseFromInputStream = client.putObject(bucketName, objectKey, inputStream);
              // 以二进制串上传Object
              PutObjectResponse putObjectResponseFromByte = client.putObject(bucketName, objectKey, byte1);
              // 以字符串上传Object
              PutObjectResponse putObjectResponseFromString = client.putObject(bucketName, objectKey, string1);
          	
              // 打印ETag
              System.out.println(putObjectFromFileResponse.getETag());
          }

          Object以文件的形式上传到BOS中,PutObject函数支持不超过5GB的Object上传。在PutObject请求处理成功后,BOS会在Header中返回Object的ETag作为文件标识。

          设置文件元信息

          文件元信息(Object Meta),是对用户在向BOS上传文件时,同时对文件进行的属性描述,主要分为分为两种:设置HTTP标准属性(HTTP Headers)和用户自定义的元信息。

          • 设定Object的Http Header

          BOS Java SDK本质上是调用后台的HTTP接口,因此用户可以在上传文件时自定义Object的Http Header。常用的http header说明如下:

          名称 描述 默认值
          Content-MD5 文件数据校验,设置后BOS会启用文件内容MD5校验,把您提供的MD5与文件的MD5比较,不一致会抛出错误
          Content-Type 文件的MIME,定义文件的类型及网页编码,决定浏览器将以什么形式、什么编码读取文件。如没有指,BOS则根据文件的扩展名自动生成,如文件没有扩展名则填默认值 application/octet-stream
          Content-Disposition 指示MINME用户代理如何显示附加的文件,打开或下载,及文件名称
          Content-Length 上传的文件的长度,超过流/文件的长度会截断,不足为实际值 流/文件时间长度
          Expires 缓存过期时间
          Cache-Control 指定该Object被下载时的网页的缓存行为
          x-bce-content-crc32 上传object的CRC值(循环冗余校验码)

          参考代码如下:

          // 初始化上传输入流
          ObjectMetadata meta = new ObjectMetadata();
          
          // 设置ContentLength大小
          meta.setContentLength(1000);
          
          // 设置ContentType
          meta.setContentType("application/json");
          
          // 设置cache-control
          meta.setCacheControl("no-cache");
          
          // 设置x-bce-content-crc32
          meta.setxBceCrc("crc");
          
          client.putObject(bucketName, objectKey, content, meta);
          • 用户自定义元信息

          BOS支持用户自定义元数据来对Object进行描述。如下代码所示:

          // 设置自定义元数据name的值为my-data
          meta.addUserMetadata("name", "my-data");
              
          // 上传Object
          client.putObject(bucketName, objectKey, content, meta);

          提示:

          • 在上面代码中,用户自定义了一个名字为”name”,值为”my-data”的元数据
          • 当用户下载此Object的时候,此元数据也可以一并得到
          • 一个Object可以有多个类似的参数,但所有的User Meta总大小不能超过2KB

          上传Object时设置存储类型

          BOS支持标准存储, 低频存储和冷存储,上传Object并存储为低频存储类型通过指定StorageClass实现,三种存储类型对应的参数如下:

          存储类型 参数
          标准存储 STANDRAD
          低频存储 STANDARD_IA
          冷存储 COLD

          以低频存储为例,代码如下:

          public void putObjectStorageClass(){
              PutObjectRequest request = new PutObjectRequest(bucketName, key, file);
              request.withStorageClass(BosClient.STORAGE_CLASS_STANDARD_IA);
              client.putObject(request);
          }

          追加上传

          上文介绍的简单上传方式,创建的Object都是Normal类型,用户不可再进行追加写,这在日志、视频监控、视频直播等数据复写较频繁的场景中使用不方便。

          正因如此,百度智能云BOS特别支持了AppendObject,即以追加写的方式上传文件。通过AppendObject操作创建的Object类型为Appendable Object,可以对该Object追加数据。AppendObject大小限制为0~5G。

          通过AppendObject方式上传示例代码如下,或参考追加上传Demo

          public void AppendObject(BosClient client, String bucketName, String objectKey, byte[] byte1, String string1) {
                  // 获取指定文件
                  File file = new File("/path/to/file.zip");
                  // 获取数据流
                  InputStream inputStream = new FileInputStream("/path/to/test.zip");
          
                  // 以文件形式上传Object
                  AppendObjectResponse appendObjectFromFileResponse = client.appendObject(bucketName, objectKey, file);
                  // 以数据流形式上传Object
                  AppendObjectResponse appendObjectResponseFromInputStream = client.appendObject(bucketName, objectKey, inputStream);
                  // 以二进制串上传Object
                  AppendObjectResponse appendObjectResponseFromByte = client.appendObject(bucketName, objectKey, byte1);
                  // 以字符串上传Object
                  AppendObjectResponse appendObjectResponseFromString = client.appendObject(bucketName, objectKey, string1);
          
                  // 打印ETag
                  System.out.println(appendObjectFromFileResponse.getETag());
                  // 打印NextAppendOffset
                  System.out.println(appendObjectFromFileResponse.getNextAppendOffset());
                  // 打印ContentMd5
                  System.out.println(appendObjectFromFileResponse.getContentMd5());
          
                  // 追加上传的示例,需要在请求中加上下次追加写的位置
                  Long nextAppendOffset = appendObjectFromFileResponse.getNextAppendOffset();
                  AppendObjectRequest appendObjectFromFileRequest = new AppendObjectRequest(bucketName,objectKey,file);
                  appendObjectFromFileRequest.setOffset(nextAppendOffset);
                  AppendObjectResponse appendObjectFromFileResponse = client.appendObject(appendObjectFromFileRequest);
              }

          分块上传

          除了通过简单上传及追加上传方式将文上传到BOS以外,BOS还提供了另外一种上传模式 —— Multipart Upload。用户可以在如下的应用场景内(但不仅限于此),使用Multipart Upload上传模式,如:

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

          下面将一步步介绍Multipart Upload的实现。假设有一个文件,本地路径为 /path/to/file.zip ,由于文件比较大,将其分块传输到BOS中。或参考分块上传Demo

          初始化Multipart Upload

          使用 initiateMultipartUpload 方法来初始化一个分块上传事件:

          // 开始Multipart Upload
          InitiateMultipartUploadRequest initiateMultipartUploadRequest =
                  new InitiateMultipartUploadRequest(bucketName, objectKey);
          InitiateMultipartUploadResponse initiateMultipartUploadResponse =
                  client.initiateMultipartUpload(initiateMultipartUploadRequest);
              
          // 打印UploadId
          System.out.println("UploadId: " + initiateMultipartUploadResponse.getUploadId());

          initiateMultipartUpload 的返回结果中含有 UploadId ,它是区分分块上传事件的唯一标识,在后面的操作中,我们将用到它。

          • 上传低频存储类型Object的初始化

          初始化低频存储的一个分块上传事件:

          public void putMultiUploadStorageClass(){
              InitiateMultipartUploadRequest iniReq = new InitiateMultipartUploadRequest(bucketName, key);
              iniReq.withStorageClass(BosClient.STORAGE_CLASS_STANDARD_IA);
              client.initiateMultipartUpload(iniReq);
          }
          • 上传冷存储类型Object的初始化

          初始化低频存储的一个分块上传事件:

          public void putMultiUploadStorageClass(){
              InitiateMultipartUploadRequest iniReq = new InitiateMultipartUploadRequest(bucketName, key);
              iniReq.withStorageClass(BosClient.STORAGE_CLASS_COLD);
              client.initiateMultipartUpload(iniReq);
          }

          上传分块

          接着,把文件分块上传。

          // 设置每块为 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();
          }

          上面代码的核心是调用 UploadPart 方法来上传每一个分块,但是要注意以下几点:

          • UploadPart 方法要求除最后一个Part以外,其他的Part大小都要大于等于5MB。但是Upload Part接口并不会立即校验上传Part的大小;只有当Complete Multipart Upload的时候才会校验。
          • 为了保证数据在网络传输过程中不出现错误,建议您在UploadPart后,使用每个分块BOS返回的Content-MD5值分别验证已上传分块数据的正确性。当所有分块数据合成一个Object后,不再含MD5值。
          • Part号码的范围是1~10000。如果超出这个范围,BOS将返回InvalidArgument的错误码。
          • 每次上传Part时都要把流定位到此次上传块开头所对应的位置。
          • 每次上传Part之后,BOS的返回结果会包含一个 PartETag 对象,它是上传块的ETag与块编号(PartNumber)的组合,在后续完成分块上传的步骤中会用到它,因此需要将其保存起来。一般来讲这些 PartETag 对象将被保存到List中。

          完成分块上传

          如下代码所示,完成分块上传:

          CompleteMultipartUploadRequest completeMultipartUploadRequest =
                  new CompleteMultipartUploadRequest(bucketName, objectKey, initiateMultipartUploadResponse.getUploadId(), partETags);
              
          // 完成分块上传
          CompleteMultipartUploadResponse completeMultipartUploadResponse =
                  client.completeMultipartUpload(completeMultipartUploadRequest);
              
          // 打印Object的ETag
          System.out.println(completeMultipartUploadResponse.getETag());

          上面代码中的 partETags 是第二部中保存的partETag的列表,BOS收到用户提交的Part列表后,会逐一验证每个数据Part的有效性。当所有的数据Part验证通过后,BOS将把这些数据part组合成一个完整的Object。

          取消分块上传事件

          用户可以使用abortMultipartUpload方法取消分块上传。

          AbortMultipartUploadRequest abortMultipartUploadRequest =
                  new AbortMultipartUploadRequest(bucketName, objectKey, uploadId);
              
          // 取消分块上传
          client.abortMultipartUpload(abortMultipartUploadRequest);

          获取未完成的分块上传事件

          用户可以使用 listMultipartUploads 方法获取Bucket内未完成的分块上传事件。

          ListMultipartUploadsRequest listMultipartUploadsRequest = 
              new ListMultipartUploadsRequest(bucketName);
          
          // 获取Bucket内所有上传事件
          ListMultipartUploadsResponse listing = client.listMultipartUploads(listMultipartUploadsRequest);
              
          // 遍历所有上传事件
          for (MultipartUploadSummary multipartUpload : listing.getMultipartUploads()) {
              System.out.println("Key: " + multipartUpload.getKey() + " UploadId: " + multipartUpload.getUploadId());
          }

          注意:

          1. 默认情况下,如果Bucket中的分块上传事件的数目大于1000,则只会返回1000个Object,并且返回结果中IsTruncated的值为True,同时返回NextKeyMarker作为下次读取的起点。
          2. 若想返回更多分块上传事件的数目,可以使用KeyMarker参数分次读取。

          获取所有已上传的块信息

          用户可以使用 listParts 方法获取某个上传事件中所有已上传的块。

          ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, objectKey, uploadId);
              
          // 获取上传的所有Part信息
          ListPartsResponse partListing = client.listParts(listPartsRequest);
              
          // 遍历所有Part
          for (PartSummary part : partListing.getParts()) {
              System.out.println("PartNumber: " + part.getPartNumber() + " ETag: " + part.getETag());
          }

          如果需要查看Object的存储类型storage class使用以下代码:

          public void listPartsStorageClass(){
              ListResponse listPartsResponse = client.listParts(bucketName, key, uploadId);
              String storageClass = listPartsResponse.getStorageClass();
          }

          注意:

          1. 默认情况下,如果Bucket中的分块上传事件的数目大于1000,则只会返回1000个Object,并且返回结果中IsTruncated的值为True,同时返回NextPartNumberMarker作为下次读取的起点。
          2. 若想返回更多分块上传事件的数目,可以使用PartNumberMarker参数分次读取。

          封装分块上传

          在Java SDK中,Bos为用户提供了putSuperObjectFromFile接口,它对分块上传涉及到的initiateMultipartUpload、UploadPart、completeMultipartUpload三个方法进行封装,用户只需调用该接口即可完成分块上传,

          File file = new File("/path/to/file.zip");
          PutSuperObjectRequest request = new PutSuperObjectRequest(bucketName, objectKey, file);
          bosClient.putSuperObjectFromFile(request);

          其中PutSuperObjectRequest的参数有:

          参数 说明
          chunkSize 分块大小,默认为5MB
          nThreads 分块上传中线程池中线程的数量,默认等于CPU的核数
          isSuperObjectUploadCanced 是否取消分块上传
          File 上传文件

          若一个大文件耗时很长,用户想结束分块上传,可调用PutSuperObjectRequest中的cancel()方法设置isSuperObjectUploadCanced为true实现取消分块上传操作。

          断点续传上传

          当用户向BOS上传大文件时,如果网络不稳定或者遇到程序崩等情况,则整个上传就失败了,失败前已经上传的部分也作废,用户不得不重头再来。这样做不仅浪费资源,在网络不稳定的情况下,往往重试多次还是无法完成上传。 基于上述场景,BOS提供了断点续传上传的能力:

          • 当网络情况一般的情况下,建议使用三步上传方式,将object分为5Mb的块,参考分块上传
          • 当您的网络情况非常差,推荐使用appendObject的方式进行断点续传,每次append 较小数据256kb,参考追加上传

          提示

          • 断点续传是分片上传的封装和加强,是用分片上传实现的;
          • 文件较大或网络环境较差时,推荐使用分片上传;

          下载文件

          BOS Java SDK提供了丰富的文件下载接口,用户可以通过以下方式从BOS中下载文件:

          • 简单流式下载
          • 下载到本地文件
          • 断点续传下载
          • 范围下载
          • 下载进度条

          完整示例代码请参考下载文件Demo

          简单流式下载

          用户可以通过如下代码将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();
          }

          注意:

          1. BosObject中包含了Object的各种信息,包含Object所在的Bucket、Object的名称、MetaData以及一个输入流,用户可以通过操作输入流将Object的内容读取到文件或者内存中。
          2. ObjectMetadata中包含了Object上传时定义的ETag,Http Header以及自定义的元数据。
          3. 通过BosObject的getObjectContent方法,还可以获取返回Object的输入流,用户可以读取这个输入流来对Object的内容进行操作。

          直接下载Object到文件

          用户可以通过如下代码直接将Object下载到指定文件:

          // 新建GetObjectRequest
          GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, objectKey);
              
          // 下载Object到文件
          ObjectMetadata objectMetadata = client.getObject(getObjectRequest, new File("/path/to/file","filename"));

          当使用上面方法将Object直接下载到文件时,方法返回ObjectMetadata对象。

          范围下载

          为了实现更多的功能,可以通过使用GetObjectRequest来指定下载范围,实现更精细化地获取Object。如果指定的下载范围是0 - 100,则返回第0到第100个字节的数据,包括第100个,共101字节的数据,即[0, 100]。

          // 新建GetObjectRequest
          GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, objectKey);
          
          // 获取0~100字节范围内的数据
          getObjectRequest.setRange(0, 100);
          
          // 获取Object,返回结果为BosObject对象
          BosObject object = client.getObject(getObjectRequest);

          通过getObjectRequest的setRange方法可以设置返回Object的范围。用户也可以用此功能实现文件的分段下载和断点续传。

          其他使用方法

          获取Object的存储类型

          Object的storage class属性分为STANDARD(标准存储), STANDARD_IA(低频存储)和COLD(冷存储),通过如下代码可以实现:

          public void getObjectStorageClass(){
              ObjectMetadata meta = client.getObjectMetadata(bucketName, key);
              String storageClass = meta.getStorageClass();
          }

          只获取ObjectMetadata

          通过 getObjectMetadata 方法可以只获取ObjectMetadata而不获取Object的实体。如下代码所示:

          ObjectMetadata objectMetadata = client.getObjectMetadata(bucketName, objectKey);

          getObjectMetadata方法返回的解析类中可供调用的参数有:

          参数 说明
          contentType Object的类型
          contentLength Object的大小
          contentMd5 Object的MD5
          etag Object的HTTP协议实体标签
          storageClass Object的存储类型
          userMetadata 如果在PutObject指定了userMetadata自定义meta,则返回此项
          xBceCrc 如果在PutObject指定了object的CRC值(循环冗余校验码),则返回此项

          变更文件存储等级

          上文中已提到,BOS支持为文件赋予STANDARD(标准存储), STANDARD_IA(低频存储)和COLD(冷存储)三种存储类型。同时,BOS java SDK也支持用户对特定文件执行存储类型变更的操作。 涉及到的参数如下:

          参数 说明
          x-bce-storage-class 指定Object的存储类型,STANDARD_IA代表低频存储,COLD代表冷存储,不指定时默认是标准存储类型。

          示例如下:

          // 标准存储转为低频存储
          CopyObjectRequest copyObjectRequest = new CopyObjectRequest(srcBucketName, srcKey, destBucketName, destKey);
          copyObjectRequest.setStorageClass("STANDARD_IA");
          client.copyObject(copyObjectRequest);
          
          // 低频存储转为冷存储
          CopyObjectRequest copyObjectRequest = new CopyObjectRequest(srcBucketName, srcKey, destBucketName, destKey);
          copyObjectRequest.setStorageClass("COLD");
          client.copyObject(copyObjectRequest);

          获取文件下载URL

          用户可以通过如下代码获取指定Object的URL:

          public String generatePresignedUrl(BosClient client, String bucketName, String objectKey, int expirationInSeconds) {
          
             URL url = client.generatePresignedUrl(<bucketName>, <objectKey>, <expirationInSeconds>);
             //指定用户需要获取的Object所在的Bucket名称、该Object名称、时间戳、URL的有效时长   
          
              return url.toString();
          }

          说明:

          • 用户在调用该函数前,需要手动设置endpoint为所属区域域名。百度智能云目前开放了多区域 支持,请参考区域选择说明。目前支持“华北-北京”、“华南-广州”和“华东-苏州”三个区域。北京区域:http://bj.bcebos.com,广州区域:http://gz.bcebos.com,苏州区域:http://su.bcebos.com
          • expirationInSeconds为指定的URL有效时长,时间从当前时间算起,为可选参数,不配置时系统默认值为1800秒。如果要设置为永久不失效的时间,可以将expirationInSeconds参数设置为 -1,不可设置为其他负数。
          • 如果预期获取的文件时公共可读的,则对应URL链接可通过简单规则快速拼接获取: http://bucketName.$region.bcebos.com/$bucket/$object

          列举存储空间中的文件

          BOS SDK支持用户通过以下两种方式列举出object:

          • 简单列举
          • 通过参数复杂列举

          除此之外,用户还可在列出文件的同时模拟文件夹,完整示例代码请参考列举文件Demo

          简单列举

          当用户希望简单快速列举出所需的文件时,可通过listObjects方法返回ListObjectsResponse对象,ListObjectsResponse对象包含了此次listObject请求的返回结果。用户可以通过ListObjectsResponse中的getContents方法获取所有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());
              }
          
          }

          注意:

          1. 默认情况下,如果Bucket中的Object数量大于1000,则只会返回1000个Object,并且返回结果中IsTruncated值为True,并返回NextMarker做为下次读取的起点。
          2. 若想增大返回Object的数目,可以使用Marker参数分次读取。

          通过参数复杂列举

          除上述简单列举外,用户还可通过设置ListObjectsReques的参数实现各种灵活的查询功能。ListObjectsReques的可设置的参数如下:

          参数 功能 使用方式
          Prefix 限定返回的object key必须以prefix作为前缀 setPrefix(String prefix)
          Delimiter 是一个用于对Object名字进行分组的字符所有名字包含指定的前缀且第一次出现。Delimiter字符之间的Object作为一组元素: CommonPrefixes setDelimiter(String delimiter)
          Marker 设定结果从marker之后按字母排序的第一个开始返回 setMarker(String marker)
          MaxKeys 限定此次返回object的最大数,最大为1000,默认值是1000。如果指定的值大于1000,按1000操作 setMaxKeys(int maxKeys)

          注意:

          1. 如果有Object以Prefix命名,当仅使用Prefix查询时,返回的所有Key中仍会包含以Prefix命名的Object。
          2. 如果有Object以Prefix命名,当使用Prefix和Delimiter组合查询时,返回的所有Key中会有Null,Key的名字不包含Prefix前缀。

          下面我们分别以几个案例说明通过参数列举的方法:

          指定最大返回条数

          // 指定最大返回条数为500
          ListObjectsRequest listObjectsRequest = new ListObjectsRequest("bucketName");
          listObjectsRequest.withMaxKeys(500);
          ListObjectsResponse listObjectsResponse = client.listObjects(listObjectsRequest);
          for(BosObjectSummary objectSummary :listObjectsResponse.getContents()) {
              System.out.println("ObjectKey:" + objectSummary.getKey());
          }

          返回指定前缀的object

          // 指定返回前缀为test的object
          ListObjectsRequest listObjectsRequest = new ListObjectsRequest("bucketName");
          listObjectsRequest.withPrefix("test");
          ListObjectsResponse listObjectsResponse = client.listObjects(listObjectsRequest);
          for(BosObjectSummary objectSummary :listObjectsResponse.getContents()) {
              System.out.println("ObjectKey:" + objectSummary.getKey());
          }

          从指定Object后返回

          // 用户可以定义不包括某object,从其之后开始返回
          ListObjectsRequest listObjectsRequest = new ListObjectsRequest("bucketName");
          listObjectsRequest.withMarker("object");
          ListObjectsResponse listObjectsResponse = client.listObjects(listObjectsRequest);
          for(BosObjectSummary objectSummary :listObjectsResponse.getContents()) {
              System.out.println("ObjectKey:" + objectSummary.getKey());
          }

          分页获取所有Object

          // 用户可设置每页最多500条记录
          ListObjectsRequest listObjectsRequest = new ListObjectsRequest("bucketName");
          listObjectsRequest.withMaxKeys(500);
          ListObjectsResponse listObjectsResponse;
          boolean isTruncated = true;
          while (isTruncated) {
              listObjectsResponse = client.listObjects(listObjectsRequest);
              isTruncated = listObjectsResponse.isTruncated();
              if (listObjectsResponse.getNextMarker() != null) {
                  listObjectsRequest.withMarker(listObjectsResponse.getNextMarker());
              }
          }

          分页获取所有特定Object后的结果

          // 用户可设置每页最多500条记录,并从某特定object之后开始获取
          ListObjectsRequest listObjectsRequest = new ListObjectsRequest("bucketName");
          listObjectsRequest.withMaxKeys(500);
          listObjectsRequest.withMarker("object");
          ListObjectsResponse listObjectsResponse;
          boolean isTruncated = true;
          while (isTruncated) {
              listObjectsResponse = client.listObjects(listObjectsRequest);
              isTruncated = listObjectsResponse.isTruncated();
              if (listObjectsResponse.getNextMarker() != null) {
                  listObjectsRequest.withMarker(listObjectsResponse.getNextMarker());
              }
          }

          分页获取所有指定前缀的Object结果

          // 用户可设置分页获取指定前缀的Object,每页最多500条记录
          ListObjectsRequest listObjectsRequest = new ListObjectsRequest("bucketName");
          listObjectsRequest.withMaxKeys(500);
          listObjectsRequest.withPrefix("object");
          ListObjectsResponse listObjectsResponse;
          boolean isTruncated = true;
          while (isTruncated) {
              listObjectsResponse = client.listObjects(listObjectsRequest);
              isTruncated = listObjectsResponse.isTruncated();
              if (listObjectsResponse.getNextMarker() != null) {
                  listObjectsRequest.withMarker(listObjectsResponse.getNextMarker());
              }
          }

          listObject方法返回的解析类中可供调用的参数有:

          参数 说明
          name Bucket名称
          prefix 匹配以prefix开始到第一次出现Delimiter字符之间的object作为一组元素返回
          marker 本次查询的起点
          maxKeys 请求返回的最大数目
          isTruncated 指明是否所有查询都返回了;false-本次已经返回所有结果,true-本次还没有返回所有结果
          contents 返回的一个Object的容器
          +key Object名称
          +lastModified 此Object最后一次被修改的时间
          +eTag Object的HTTP协议实体便签
          +storageClass Object的存储形态
          +size Object的内容的大小(字节数)
          +owner Object对应Bucket所属用户信息
          ++id Bucket Owner的用户ID
          ++displayName Bucket Owner的名称

          模拟文件夹功能

          在BOS的存储结果中是没有文件夹这个概念的,所有元素都是以Object来存储,但BOS的用户在使用数据时往往需要以文件夹来管理文件。 因此,BOS提供了创建模拟文件夹的能力,其本质上来说是创建了一个size为0的Object。对于这个Object可以上传下载,只是控制台会对以”/“结尾的Object以文件夹的方式展示。

          用户可以通过 Delimiter 和 Prefix 参数的配合模拟出文件夹功能。Delimiter 和 Prefix 的组合效果是这样的:

          如果把 Prefix 设为某个文件夹名,就可以罗列以此 Prefix 开头的文件,即该文件夹下递归的所有的文件和子文件夹(目录)。文件名在Contents中显示。 如果再把 Delimiter 设置为 “/” 时,返回值就只罗列该文件夹下的文件和子文件夹(目录),该文件夹下的子文件名(目录)返回在 CommonPrefixes 部分,子文件夹下递归的文件和文件夹不被显示。

          如下是几个应用方式:

          列出Bucket内所有文件

          当用户需要获取Bucket下的所有文件时,可以参考分页获取所有Object

          递归列出目录下所有文件

          可以通过设置 Prefix 参数来获取某个目录下所有的文件:

          // 构造ListObjectsRequest请求
          ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
              
          // 递归列出fun目录下的所有文件
          listObjectsRequest.setPrefix("fun/");
              
          ListObjectsResponse listing = client.listObjects(listObjectsRequest);
              
          // 遍历所有Object
          System.out.println("Objects:");
          for (BosObjectSummary objectSummary : listing.getContents()) {
              System.out.println(objectSummary.getKey());
          	}
          }

          输出:

          Objects:
          fun/
          fun/movie/001.avi
          fun/movie/007.avi
          fun/test.jpg

          查看目录下的文件和子目录

          PrefixDelimiter 结合的情况下,可以列出目录下的文件和子目录:

          // 构造ListObjectsRequest请求
          ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
              
          // "/" 为文件夹的分隔符
          listObjectsRequest.setDelimiter("/");
              
          // 列出fun目录下的所有文件和文件夹
          listObjectsRequest.setPrefix("fun/");
              
          ListObjectsResponse listing = client.listObjects(listObjectsRequest);
              
          // 遍历所有Object
          System.out.println("Objects:");
          for (BosObjectSummary objectSummary : listing.getContents()) {
              System.out.println(objectSummary.getKey());
          }
              
          // 遍历所有CommonPrefix
          System.out.println("\nCommonPrefixs:");
          for (String commonPrefix : listing.getCommonPrefixes()) {
              System.out.println(commonPrefix);
          }

          输出:

          Objects:
          fun/
          fun/test.jpg
          
          CommonPrefixs:
          fun/movie/

          返回的结果中, ObjectSummaries 的列表中给出的是fun目录下的文件。而 CommonPrefixs 的列表中给出的是fun目录下的所有子文件夹。可以看出 fun/movie/001.avifun/movie/007.avi 两个文件并没有被列出来,因为它们属于 fun 文件夹下的 movie 目录。

          列举Bucket中object的存储属性

          当用户完成上传后,如果需要查看指定Bucket中的全部Object的storage class属性,可以通过如下代码实现:

          public void listObjectsStorageClass(){
              ListObjectsResponse listObjectResponse = client.listObjects("bucketName");
              List<BosObjectSummary> objectList = listObjectResponse.getContents();
              for(int i=0; i<objectList.length(); i++) {
                  System.out.println(objectList[i].getStorageClass());
              }
          }

          获取目录容量概览

          用户可以通过如下代码获取Bucket或指定前缀下的当前容量、Object数、文件数。

          public void stateSummary(BosClient client, String bucketName, String prefix) {
          
              // 获取Bucket下的当前容量、Object数、文件数
              StateSummaryResponse response = client.stateSummary(bucketName);
              System.out.println("currSize : " + response.getTotalSize());
              System.out.println("objectsCount : " + response.getObjectsCount());
              System.out.println("filesCount : " + response.getFilesCount());
          
          }

          获取带有指定前缀的object容量、Object数、文件数:

          public StateSummaryResponse stateSummaryWithPrefix(BosClient client, String bucketName, String prefix) {
          
              StateSummaryRequest request = new StateSummaryRequest();
              request.setBucketName(this.bucketName);
              request.setPrefix("dir/x");
              StateSummaryResponse response = client.stateSummary(request);
          
              return response;
          }

          Object权限控制

          设置Object的访问权限

          目前BOS支持两种方式设置ACL。第一种是使用Canned Acl,在PutObjectAcl的时候,通过头域的"x-bce-acl"或者"x-bce-grant-permission'来设置object访问权限,当前可设置的权限包括private和public-read,两种类型的header不可以同时在一个请求中出现。第二种方式是上传一个ACL文件。

          详细信息请参考设置Object权限控制,或查看Demo样例

          1、通过使用头域的"x-bce-acl"或者"x-bce-grant-permission'来设置object访问权限

          • set object acl 第一种方式(以请求头方式设置)
          SetObjectAclRequest setObjectAclRequest = new SetObjectAclRequest("yourBucketName","objectKey",CannedAccessControlList.PublicRead);
          client.setObjectAcl(setObjectAclRequest);
          • set object acl 第一种方式(以请求头方式设置 xBceGrantRead)
          String xBceGrantRead = "id=\"user_id1\""+",id=\"user_id2\"";
          SetObjectAclRequest setObjectAclRequest = new SetObjectAclRequest();
          setObjectAclRequest.withBucketName("yourBucketName");
          setObjectAclRequest.withKey("objectKey");
          setObjectAclRequest.setxBceGrantRead(xBceGrantRead);
          client.setObjectAcl(setObjectAclRequest);
          • set object acl 第一种方式(已请求头方式设置 xBceGrantFullControl)
          String xBceGrantFullControl = "id=\"user_id1\""+",id=\"user_id2\"";
          SetObjectAclRequest setObjectAclRequest = new SetObjectAclRequest();
          setObjectAclRequest.withBucketName("yourBucketName");
          setObjectAclRequest.withKey("objectKey");
          setObjectAclRequest.setxBceGrantFullControl(xBceGrantFullControl);
          client.setObjectAcl(setObjectAclRequest);

          2、通过setObjectAcl设置object访问权限

          • set object acl 第二种方式(json字符串)
          String jsonObjectAcl = "{\"accessControlList\":["+ "{\"grantee\":[{\"id\":\"*\"}], "+ "\"permission\":[\"FULL_CONTROL\"]"+"}]}";
          
          SetObjectAclRequest setObjectAclRequest = new SetObjectAclRequest("yourBucketName","objectKey",jsonObjectAcl);
          
          client.setObjectAcl(setObjectAclRequest);
          • set object acl 第二种方式,用户只需指定指定参数即可
          List<Grant> grants = new ArrayList<Grant>();
          List<Grantee> grantees = new ArrayList<Grantee>();
          List<Permission> permissions = new ArrayList<Permission>();
          
          // 授权给特定用户
          grantees.add(new Grantee("user_id1"));
          grantees.add(new Grantee("user_id2"));
          grantees.add(new Grantee("user_id3"));
          
          // 设置权限
          permissions.add(Permission.READ);
          grants.add(new Grant().withGrantee(grantees).withPermission(permissions));
          
          SetObjectAclRequest setObjectAclRequest = new SetObjectAclRequest("yourBucketName","objectKey", grants);
          client.setObjectAcl(setObjectAclRequest);

          查看Object的权限

          如下代码可以查Object的权限:

          GetObjectAclRequest getObjectRequest = new GetObjectAclRequest();
          getObjectRequest.withBucketName("yourBucketName");
          getObjectRequest.withKey("objectKey");
          GetObjectAclResponse response = client.getObjectAcl(getObjectRequest);

          getObjectAcl方法返回的解析类中可供调用的参数有:

          参数 说明
          accessControlList 标识Object的权限列表
          grantee 标识被授权人
          -id 被授权人ID
          permission 标识被授权人的权限

          删除Object的权限

          如下代码可以删除Object的权限:

          DeleteObjectAclRequest deleteObjectAclRequest = new DeleteObjectAclRequest("yourBucketName","objectKey");
          
          client.deleteObjectAcl(deleteObjectAclRequest);

          删除文件

          示例代码可以参考删除文件Demo

          删除单个文件

          可参考如下代码删除了一个Object:

          public void deleteObject(BosClient client, String bucketName, String objectKey) {
          
              // 删除Object
              client.deleteObject(<bucketName>, <objectKey>);           //指定要删除的Object所在Bucket名称和该Object名称
          }

          删除多个文件

          删除多个文件

          可参考如下两种方法删除多个Object:

          // 1、以Json格式的字符串
          String jsonObjectKeys = "{\"objects\": ["+"{\"key\": \"token1.h\"},"+"{\"key\": \"token2.h\"}"+"]}";
          DeleteMultipleObjectsRequest request = new DeleteMultipleObjectsRequest();
          request.setBucketName("yourBucketName");
          request.setJsonDeleteObjects(jsonObjectKeys);
          client.deleteMultipleObjects(request);
          // 2、用户只需指定指定参数即可
          List<String> objectKeys = new ArrayList<String>();
          objectKeys.add("object1");
          objectKeys.add("object2");
          DeleteMultipleObjectsRequest request = new DeleteMultipleObjectsRequest();
          request.setBucketName("yourBucketName");
          request.setObjectKeys(objectKeys);
          DeleteMultipleObjectsResponse response = client.deleteMultipleObjects(request);

          支持一次请求内最多删除1000个Object。 消息体(body)不超过2M。 返回的消息体中只包含删除过程中出错的Object结果;如果所有Object都删除都成功的话,则没有消息体。

          查看文件是否存在

          用户可通过如下操作查看某文件是否存在:

          // 存在返回true,不存在返回false,其他异常会被抛出
          bool exists = client.doesObjectExist("bucketName", "objectKey");

          获取及更新文件元信息

          文件元信息(Object Metadata),是对用户上传BOS的文件的属性描述,分为两种:HTTP标准属性(HTTP Headers)和User Meta(用户自定义元信息)。

          获取文件元信息

          参考只获取ObjectMetadata,或Demo

          修改文件元信息

          BOS修改Object的Metadata通过拷贝Object实现。即拷贝Object的时候,把目的Bucket设置为源Bucket,目的Object设置为源Object,并设置新的Metadata,通过拷贝自身实现修改Metadata的目的。如果不设置新的Metadata,则报错。

            public void setObjectMeta(BosClient client, String bucketName, String objectKey, ObjectMetadata newObjectMetadata) {
                  
                  CopyObjectRequest request = new CopyObjectRequest(bucketName, objectKey, bucketName, objectKey);
          
                  // 设置新的ObjectMetadata
                  request.setNewObjectMetadata(newObjectMetadata);
          
                  // 拷贝Object
                  CopyObjectResponse copyObjectResponse = client.copyObject(request);
          
                  // 打印结果
                  System.out.println("ETag: " + copyObjectResponse.getETag() + " LastModified: " + copyObjectResponse.getLastModified());
              }

          拷贝文件

          示例代码可以参考拷贝文件Demo

          拷贝一个文件

          用户可以通过copyObject方法拷贝一个Object,如下代码所示:

          public void copyObject(BosClient client, String srcBucketName, String srcKey, String destBucketName, String destKey) {
              
              // 拷贝Object
              CopyObjectResponse copyObjectResponse = client.copyObject(srcBucketName, srcKey, destBucketName, destKey);
              
              // 打印结果
              System.out.println("ETag: " + copyObjectResponse.getETag() + " LastModified: " + copyObjectResponse.getLastModified());
          }

          copyObject 方法返回一个 CopyObjectResponse 对象,该对象中包含了新Object的ETag和修改时间。

          通过CopyObjectRequest拷贝Object

          用户也可以通过 CopyObjectRequest 实现Object的拷贝,如下代码所示:

          // 初始化BosClient
          BosClient client = ...;
              
          // 创建CopyObjectRequest对象
          CopyObjectRequest copyObjectRequest = new CopyObjectRequest(srcBucketName, srcKey, destBucketName, destKey);
              
          // 设置新的Metadata
          Map<String, String> userMetadata = new HashMap<String, String>();
          userMetadata.put('<user-meta-key>','<user-meta-value>');
          ObjectMetadata meta = new ObjectMetadata();
          meta.setUserMetadata(userMetadata);
          copyObjectRequest.setNewObjectMetadata(meta);
              
          // 复制Object
          CopyObjectResponse copyObjectResponse = client.copyObject(copyObjectRequest);
              
          System.out.println("ETag: " + copyObjectResponse.getETag() + " LastModified: " + copyObjectResponse.getLastModified());

          CopyObjectRequest 允许用户修改目的Object的ObjectMeta,同时也提供 MatchingETagConstraints 参数的设定。

          设置Object的Copy属性

          BOS同时会提供CopyObject接口用于将一个已经存在的Object拷贝到另外一个Object,拷贝过程中会对源Object的Etag或修改状态进行判断,根据判断结果决定是否执行拷贝。详细的参数解释如下:

          名称 类型 描述 是否必需
          x-bce-copy-source-if-match String 如果源Object的ETag值和用户提供的ETag相等,则执行拷贝操作,否则拷贝失败。
          x-bce-copy-source-if-none-match String 如果源Object的ETag和用户提供的ETag不相等,则执行拷贝操作,否则拷贝失败。
          x-bce-copy-source-if-unmodified-since String 如果源object在x-bce-copy-source-if-unmodified-since之后没被修改,则执行拷贝操作,否则拷贝失败。
          x-bce-copy-source-if-modified-since String 如果源object在x-bce-copy-source-if-modified-since之后被修改了,则执行拷贝操作,否则拷贝失败。

          对应的示例代码:

          // 初始化BosClient
          BosClient client = ...;
          
          // 创建CopyObjectRequest对象
          CopyObjectRequest copyObjectRequest = new CopyObjectRequest(srcBucketName, srcKey, destBucketName, destKey);
          
          // 设置新的Metadata
          Map<String, String> userMetadata = new HashMap<String, String>();
          userMetadata.put("<user-meta-key>","<user-meta-value>");
                  
          meta.setUserMetadata(userMetadata);
          copyObjectRequest.setNewObjectMetadata(meta);
          
          //copy-source-if-match
          copyObjectRequest.withETag("111111111183bf192b57a4afc76fa632");
          //copy-source-if-none-match
          copyObjectRequest.withNoMatchingETagConstraint("111111111183bf192b57a4afc76fa632");
                  
          Date modifiedSinceConstraint = new Date();    
          SimpleDateFormat df = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.UK);  
          df.setTimeZone(new java.util.SimpleTimeZone(0, "GMT"));        
          String date = df.format(modifiedSinceConstraint);
          
          //copy-source-if-modified-since
          copyObjectRequest.withModifiedSinceConstraint(date);
          
          //copy-source-if-unmodified-since
          copyObjectRequest.withUnmodifiedSinceConstraint(date);
          
          // 复制Object
          CopyObjectResponse copyObjectResponse = client.copyObject(copyObjectRequest);
          
          System.out.println("ETag: " + copyObjectResponse.getETag() + " LastModified: " + copyObjectResponse.getLastModified());

          同步Copy功能

          当前BOS的CopyObject接口是通过同步方式实现的。同步方式下,BOS端会等待Copy实际完成才返回成功。同步Copy能帮助用户更准确的判断Copy状态,但用户感知的复制时间会变长,且复制时间和文件大小成正比。

          同步Copy方式更符合业界常规,提升了与其它平台的兼容性。同步Copy方式还简化了BOS服务端的业务逻辑,提高了服务效率。

          如果您使用bce-java-sdk-0.10.8版本之前的SDK,有可能会出现复制请求成功,但文件实际复制失败的情况,所以建议您使用最新版本SDK。

          分块拷贝

          除了通过CopyObject接⼝拷贝文件以外,BOS还提供了另外一种拷贝模式——Multipart Upload Copy。用户可以在如下的应用场景内(但不仅限于此),使用Multipart Upload Copy,如:

          • 需要支持断点拷贝。
          • 拷贝超过5GB大小的文件。
          • 网络条件较差,和BOS的服务器之间的连接经常断开。

          下面将介绍分步实现三步拷贝。

          三步拷贝包含init、“拷贝分块”和complete三步,其中init和complete的操作同分块上传一致。

          为了便于理解,下面提供三步拷贝完整代码:

          // 第一步 init
          InitiateMultipartUploadRequest initiateMultipartUploadRequest =
                  new InitiateMultipartUploadRequest("targetBucketName","targetObjectName");
          InitiateMultipartUploadResponse initiateMultipartUploadResponse =
                  client.initiateMultipartUpload(initiateMultipartUploadRequest);
          
          // 第二步 分块拷贝
          long left_size=client.getObjectMetadata("sourceBucketName","sourceObjectName").getContentLength();
          long skipBytes = 0;
          int partNumber = 1;
          List<PartETag> partETags = new ArrayList<PartETag>();
          
          while (left_size > 0) {
              long partSize = 1024 * 1024 * 1L;
              if (left_size < partSize) {
                  partSize = left_size;
              }
              UploadPartCopyRequest uploadPartCopyRequest = new UploadPartCopyRequest();
              uploadPartCopyRequest.setBucketName("targetBucketName");
              uploadPartCopyRequest.setKey("targetObjectName");
              uploadPartCopyRequest.setSourceBucketName("sourceBucketName");
              uploadPartCopyRequest.setSourceKey("sourceObjectName");
              uploadPartCopyRequest.setUploadId(initiateMultipartUploadResponse.getUploadId());
              uploadPartCopyRequest.setPartSize(partSize);
              uploadPartCopyRequest.setOffSet(skipBytes);
              uploadPartCopyRequest.setPartNumber(partNumber);
              UploadPartCopyResponse uploadPartCopyResponse = client.uploadPartCopy(uploadPartCopyRequest);
              // 将返回的PartETag保存到List中
              PartETag partETag = new PartETag(partNumber,uploadPartCopyResponse.getETag());
              partETags.add(partETag);
              left_size -= partSize;
              skipBytes += partSize;
              partNumber+=1;
          }
          
          // 第三步 complete
          CompleteMultipartUploadRequest completeMultipartUploadRequest =
                  new CompleteMultipartUploadRequest("targetBucketName", "targetObjectName", initiateMultipartUploadResponse.getUploadId(), partETags);
          CompleteMultipartUploadResponse completeMultipartUploadResponse =
                  client.completeMultipartUpload(completeMultipartUploadRequest);

          注意:

          1. offset参数以字节为单位,为分块的开始偏移位置。
          2. size参数以字节为单位,定义每个分块的大小,除最后一个Part以外,其他的Part大小都要大于 5MB。

          选取文件

          BOS Java SDK提供了SelectObject接口,用于向Bucket中指定object执行SQL语句,选取出指定内容返回,请参考选取Object。目前支持object类型为CSV(包括TSV等类CSV文件)和JSON文件:

          示例代码可以参考选取文件Demo

          • 选取CSV文件
          • 选取JSON文件

          选取CSV文件

          Java SDK选取CSV文件请参考以下代码:

          final String csvContent = "header1,header2,header3\r\n" +
                                    "1,2,3.4\r\n" +
                                    "a,b,c\r\n" +
                                    "\"d\",\"e\",\"f\"\r\n" +
                                    "true,false,true\r\n" +
                                    "2006-01-02 15:04:06,2006-01-02 16:04:06,2006-01-02 17:04:06";
          client.putObject("bucketName", "test-csv", new ByteArrayInputStream(csvContent.getBytes()));
          
          SelectObjectRequest request = new SelectObjectRequest("bucketName", "test-csv")
                  .withSelectType("csv")                                   
                  .withExpression("select * from BosObject limit 3")
                  .withInputSerialization(new InputSerialization()
                          .withCompressionType("NONE")
                          .withFileHeaderInfo("NONE")
                          .withRecordDelimiter("\r\n")
                          .withFieldDelimiter(",")
                          .withQuoteCharacter("\"")
                          .withCommentCharacter("#"))
                  .withOutputSerialization(new OutputSerialization()
                          .withOutputHeader(false)
                          .withQuoteFields("ALWAYS")
                          .withRecordDelimiter("\n")
                          .withFieldDelimiter(",")
                          .withQuoteCharacter("\""))
                  .withRequestProgress(false);
          SelectObjectResponse response = client.selectObject(request);
          
          // 输出返回的记录
          SelectObjectResponse.Messages messages = response.getMessages();
          while (messages.hasNext()) {
              SelectObjectResponse.CommonMessage message = messages.next();
              if (message.Type.equals("Records")) {
                  for (String record: message.getRecords()) {
                      System.out.println(record);
                  }
              }
          }

          选取CSV文件输出的结果:

          "header1","header2","header3"
          "1","2","3.4"
          "a","b","c"

          注意:

          • Unix/Linux系统里,每行结尾只有"<换行>",即"\n";
          • Windows系统里面,每行结尾是"<回车><换行>",即"\r\n";
          • Mac系统里,每行结尾是"<换行>",即"\n",只有 v9 之前 Mac OS 才是用 '\r'。
          • 根据文件内容,设置合适的recordDelimiter。

          选取JSON文件

          Java SDK选取JSON文件请参考以下代码:

          final String jsonContent = "{\n" +
                  "\t\"name\": \"Smith\",\n" +
                  "\t\"age\": 16,\n" +
                  "\t\"org\": null\n" +
                  "}\n" +
                  "{\n" +
                  "\t\"name\": \"charles\",\n" +
                  "\t\"age\": 27,\n" +
                  "\t\"org\": \"baidu\"\n" +
                  "}\n" +
                  "{\n" +
                  "\t\"name\": \"jack\",\n" +
                  "\t\"age\": 35,\n" +
                  "\t\"org\": \"bos\"\n" +
                  "}";
          client.putObject("bucketName", "test-json", new ByteArrayInputStream(jsonContent.getBytes()));
          
          SelectObjectRequest request = new SelectObjectRequest("bucketName", "test-json")
                  .withSelectType("json")
                  .withExpression("select * from BosObject where age > 20")
                  .withInputSerialization(new InputSerialization()
                          .withCompressionType("NONE")
                          .withJsonType("LINES"))
                  .withOutputSerialization(new OutputSerialization()
                          .withRecordDelimiter("\n"))
                  .withRequestProgress(false);
          SelectObjectResponse response = client.selectObject(request);
          
          // 输出返回的记录
          SelectObjectResponse.Messages messages = response.getMessages();
          while (messages.hasNext()) {
              SelectObjectResponse.CommonMessage message = messages.next();
              if (message.Type.equals("Records")) {
                  for (String record: message.getRecords()) {
                      System.out.println(record);
                  }
              }
          }

          选取JSON文件输出的结果:

          {"name":"charles","age":27,"org":"baidu"}
          {"name":"jack","age":35,"org":"bos"}

          注意,对于CSV和JSON文件查询时,两者初始化SelectObjectRequest的参数有很大不同,详细参数设置请参考SelectObject接口

          上一篇
          Bucket管理
          下一篇
          数据处理及使用