Object管理
所有文档

          对象存储 BOS

          Object管理

          上传Object

          最简单的上传

          • 基本流程

            1. 创建BosClient。
            2. 调用putObject()方法,可以通过如下四种方式上传Object:字符串、DataUrl、文件和blob对象的形式。
          • 示例代码

            function done(response) {
                // 上传完成
            }
            function fail(fail) {
                // 上传失败
            }
            
            // 以字符串形式上传
            client.putObjectFromString(bucket, object, 'hello world')
              .then(done)
              .catch(fail);
            
            // 以buffer形式上传
            var buffer = new Buffer('hello world'); client.putObject(bucket, object, buffer)
              .then(done)
              .catch(fail);
            
            // 以文件形式上传,仅支持Node.js环境
            client.putObjectFromFile(bucket, object, <path-to-file>)
              .then(done)
              .catch(fail);
            
            // 以blob对象形式上传,仅支持浏览器环境
            client.putObjectFromBlob(bucket, object, <blob对象>)
              .then(done)
              .catch(fail);

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

          设定Object的Http Header和自定义Meta数据

          SDK本质上是调用后台的HTTP接口,因此BOS服务允许用户自定义Http Header。同时也允许用户对要上传的Object添加自定义Meta信息。以putObjectFromFile()函数为例,可以用以下代码来处理:

          • 示例代码

            let options = {
              'Content-Length': <file.size>, // 添加http header
              'Content-Type': 'application/json', // 添加http header
              'Cache-Control': 'public, max-age=31536000', // 指定缓存指令
              'Content-Disposition': 'attachment; filename="example.jpg"', // 指示回复的内容该以何种形式展示
            
              'x-bce-meta-foo1': 'bar1', // 添加自定义meta信息
              'x-bce-meta-foo2': 'bar2', // 添加自定义meta信息
              'x-bce-meta-foo3': 'bar3' // 添加自定义meta信息
            }
            client.putObjectFromFile(bucket, object, <path-to-file>, options)
              .then(done)
              .catch(fail);

            注意:自定义Meta信息的key需要以x-bce-meta-开头。

          查看Bucket中的Object

          简单查询

          查看Bucket中Object列表。

          • 基本流程

            1. 创建BosClient。
            2. 执行listObjects()方法。
          • 示例代码

            client.listObjects(<bucketName>)
              .then(function (response) {
                  var contents = response.body.contents;
                  for (var i = 0, l = contents.length; i < l; i++) {
                      console.log(contents[i].key);
                  }
              })
              .catch(function (error) {
                  // 查询失败
              });

            注意:

            • 默认情况下,如果Bucket中的Object数量大于1000,则只会返回1000个Object,并且返回结果中IsTruncated值为True,并返回NextMarker做为下次读取的起点。
            • 若想获取更多的Object,可以使用Marker参数分次读取,请参考扩展查询

          扩展查询

          用户可以通过设置listObjects参数来完成更多扩展查询操作设置。可以设置的扩展参数如下:

          参数名称 说明 默认值
          maxKeys 设定此次返回Object的最大个数,不可超过1000。 1000
          prefix 设定objectKey的前缀,前缀是指objectKey包含并以prefix的值作为开始。
          通常与delimiter配合在查询模拟文件夹中使用。
          -
          delimiter 是一个分隔符,用来对objectKey进行分层。
          通常与prefix配合在查询模拟文件夹中使用。
          从prefix开始到第一次出现delimiter字符之间的objectKey称为:commonPrefixes。
          -
          marker 是一个字符串,用来设定返回结果的起始位置。
          设定marker值之后,返回的Object会从marker值之后按字母排序开始返回。
          -
          • 示例代码

            // 设置参数
            var options = {
                delimiter: '/',
                marker: '123'
            };
            
            client.listObjects(<bucketName>, options)
                .then(function (response) {
                    var contents = response.body.contents;
                    for (var i = 0, l = contents.length; i < l; i++) {
                        console.log(contents[i].key);
                    }
                })
                .catch(function (error) {
                    // 查询失败
                });

          查询模拟文件夹

          由于BOS本身是一个(<Key>,<Value>)的存储系统,所以原则上并不会存在“文件夹”的概念,但您可以通过 delimiterprefix 参数的配合进行文件夹功能模拟。

          假设Bucket中有5个文件:bos.jpg,fun/,fun/test.jpg,fun/movie/001.avi,fun/movie/007.avi,可以把 “/” 符号作为分隔符模拟文件夹。

          递归列出模拟文件夹下所有文件

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

          // 设置参数
          let options = {
          prefix: 'fun/' // 递归列出fun目录下的所有文件
          };
          
          
          client.listObjects(<bucketName>, options)
          .then(function (response) {
              console.log('Objects:');
              var contents = response.body.contents;
              for (var i = 0, l = contents.length; i < l; i++) {
                  console.log(contents[i].key);
              }
          })
          .catch(function (error) {
              // 查询失败
          });

          输出:

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

          查看模拟文件夹下的文件和子文件夹

          PrefixDelimiter 结合的情况下,可以列出模拟文件夹下的文件和子文件夹:

          // 设置参数
          let options = {
              prefix: 'fun/', // 列出fun目录下的所有文件和文件夹
              delimiter: '/' // "/" 为文件夹的分隔符
          };
          
          client.listObjects(<bucketName>, options)
          .then(function (response) {
              console.log('Objects:');
              var contents = response.body.contents;
              for (var i = 0, l = contents.length; i < l; i++) {
                  console.log(contents[i].key);
              }
              console.log('CommonPrefixs:');
              var commonPrefixes = response.body.commonPrefixes;
              for (i = 0, l = commonPrefixes.length; i < l; i++) {
                  console.log(commonPrefixes[i]);
              }
          })
          .catch(function (error) {
              // 查询失败
          });

          输出:

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

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

          获取Object(仅支持Node.js)

          简单的获取Object

          用户可以通过如下代码将Object读取到一个流中。

          • 基本流程

            1. 创建BosClient。
            2. 执行getObject()。
          • 示例代码

            let range = '0-100';
            client.getObject(<BucketName>, <Key>, range)
                .then(function(response) {
                    let buffer = response.body;
                });

            说明: 设置range为0-100表示只获取0到100字节的数据,您可以用此功能实现文件的分段下载和断点续传。如果不设置range,则获取整个Object。

          下载Object到指定路径

          用户可以通过如下代码直接将Object下载到指定路径。

          • 基本流程

            1. 创建BosClient。
            2. 执行client.getObject( )操作。
            3. Object可以直接下载到指定路径。
          • 示例代码

            let range = '0-100';
            client.getObjectToFile(<bucketName>, <key>, <filePath>, range)
                .then(function() {
                    // 下载完成
                });

            说明: 设置range为0-100表示只获取0到100字节的数据,您可以用此功能实现文件的分段下载和断点续传。如果不设置range,则获取整个Object。filePath为文件完整路径,包含文件名称及类型。

          只获取ObjectMetadata

          通过 getObjectMetadata() 方法可以只获取ObjectMetadata而不获取Object的实体。

          • 示例代码

            client.getObjectMetadata(<BucketName>, <ObjectKey>)
              .then(function(response) {
                  console.dir(response.http_headers);
              });

          删除Object

          • 基本流程

            1. 创建BosClient。
            2. 执行deleteObject()方法。
          • 示例代码

            // 删除Object
            //指定要删除的Object所在Bucket名称和该Object名称
            client.deleteObject(<BucketName>, <ObjectKey>);   
          • 完整示例

            • 浏览器端: let BosClient = baidubce.sdk.BosClient
            • Node.js: import {BosClient} from '@baiducloud/sdk'
            let config = {
                endpoint: <EndPoint>,            //Bucket所在区域域名
                credentials: {
                    ak: <AccessKeyID>,           //您的AK
                    sk: <SecretAccessKey>       //您的SK
                }
            };
            
            let client = new BosClient(config);
            
            client.deleteObject(<BucketName>, <ObjectKey>);

          拷贝Object

          简单拷贝Object

          • 基本流程

            1. 创建BosClient。
            2. 执行copyObject( )方法。
          • 示例代码

            let options = {
              x-bce-meta-foo1: 'bar1', // 覆盖自定义meta信息
              x-bce-meta-foo2: 'bar2', // 覆盖自定义meta信息
              x-bce-meta-foo3: 'bar3' // 覆盖自定义meta信息
            }
            //SrcBucketName, SrcKey为原地址,DestBucketName, DestKey为拷贝到的目的地址
            client.copyObject(<SrcBucketName>, <SrcKey>, <DestBucketName>, <DestKey>, options);

          Object的分块上传

          除了通过putObject()方法上传文件到BOS以外,BOS还提供了另外一种上传模式:分块上传(Multipart Upload)。用户可以在如下的应用场景内(但不仅限于此),使用分块上传模式,如:

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

          分块上传比直接上传稍微复杂一点,分块上传需要分为三个阶段:

          • 开始上传(initiateMultipartUpload)
          • 上传分块(uploadPartFromBlob)
          • 上传完成(completeMultipartUpload)

          浏览器端代码示例

          对文件进行分块

          let PART_SIZE = 5 * 1024 * 1024; // 指定分块大小
          
          function getTasks(file, uploadId, bucketName, key) {
              let leftSize = file.size;
              let offset = 0;
              let partNumber = 1;
          
              let tasks = [];
          
              while (leftSize > 0) {
                  let partSize = Math.min(leftSize, PART_SIZE);
                  tasks.push({
                      file: file,
                      uploadId: uploadId,
                      bucketName: bucketName,
                      key: key,
                      partNumber: partNumber,
                      partSize: partSize,
                      start: offset,
                      stop: offset + partSize - 1
                  });
          
                  leftSize -= partSize;
                  offset += partSize;
                  partNumber += 1;
              }
              return tasks;
          }

          处理每个分块的上传逻辑

          function uploadPartFile(state, client) {
              return function(task, callback) {
                  let blob = task.file.slice(task.start, task.stop + 1);
                  client.uploadPartFromBlob(task.bucketName, task.key, task.uploadId, task.partNumber, task.partSize, blob)
                      .then(function(res) {
                          ++state.loaded;
                          callback(null, res);
                      })
                      .catch(function(err) {
                          callback(err);
                      });
              };
          }

          初始化uploadID,开始上传分块,并完成上传

          let uploadId;
          client.initiateMultipartUpload(bucket, key, options)
              .then(function(response) {
                  uploadId = response.body.uploadId; // 开始上传,获取服务器生成的uploadId
          
                  let deferred = sdk.Q.defer();
                  let tasks = getTasks(blob, uploadId, bucket, key);
                  let state = {
                      lengthComputable: true,
                      loaded: 0,
                      total: tasks.length
                  };
          
                  // 为了管理分块上传,使用了async(https://github.com/caolan/async)库来进行异步处理
                  let THREADS = 2; // 同时上传的分块数量
                  async.mapLimit(tasks, THREADS, uploadPartFile(state, client), function(err, results) {
                      if (err) {
                          deferred.reject(err);
                      } else {
                          deferred.resolve(results);
                      }
                  });
                  return deferred.promise;
              })
              .then(function(allResponse) {
                  let partList = [];
                  allResponse.forEach(function(response, index) {
                      // 生成分块清单
                      partList.push({
                          partNumber: index + 1,
                          eTag: response.http_headers.etag
                      });
                  });
                  return client.completeMultipartUpload(bucket, key, uploadId, partList); // 完成上传
              })
              .then(function (res) {
                  // 上传完成
              })
              .catch(function (err) {
                  // 上传失败,添加您的代码
                  console.error(err);
              });

          Node.js端分块上传

          对文件进行分块,并初始化UploadID,上传分块

          let PART_SIZE = 5 * 1024 * 1024; // 指定分块大小
          let uploadId;
          client.initiateMultipartUpload(bucket, key, options)
              .then(function(response) {
                  uploadId = response.body.uploadId; // 开始上传,获取服务器生成的uploadId
          
                  let deferred = sdk.Q.defer();
                  let tasks = getTasks(blob, uploadId, bucket, key);
                  let state = {
                      lengthComputable: true,
                      loaded: 0,
                      total: tasks.length
                  };
          
                  // 为了管理分块上传,使用了async(https://github.com/caolan/async)库来进行异步处理
                  let THREADS = 2; // 同时上传的分块数量
                  async.mapLimit(tasks, THREADS, uploadPartFile(state, client), function(err, results) {
                      if (err) {
                          deferred.reject(err);
                      } else {
                          deferred.resolve(results);
                      }
                  });
                  return deferred.promise;
              })
              .then(function(allResponse) {
                  let partList = [];
                  allResponse.forEach(function(response, index) {
                      // 生成分块清单
                      partList.push({
                          partNumber: index + 1,
                          eTag: response.http_headers.etag
                      });
                  });
                  return client.completeMultipartUpload(bucket, key, uploadId, partList); // 完成上传
              })
              .then(function (res) {
                  // 上传完成
              })
              .catch(function (err) {
                  // 上传失败,添加您的代码
                  console.error(err);
              });
          
          function getTasks(file, uploadId, bucketName, key) {
              let leftSize = file.size;
              let offset = 0;
              let partNumber = 1;
          
              let tasks = [];
          
              while (leftSize > 0) {
                  let partSize = Math.min(leftSize, PART_SIZE);
                  tasks.push({
                      file: file,
                      uploadId: uploadId,
                      bucketName: bucketName,
                      key: key,
                      partNumber: partNumber,
                      partSize: partSize,
                      start: offset,
                      stop: offset + partSize - 1
                  });
          
                  leftSize -= partSize;
                  offset += partSize;
                  partNumber += 1;
              }
              return tasks;
          }
          function uploadPartFile(state, client) {
              return function(task, callback) {
                  return client.uploadPartFromFile(task.bucketName, task.key, task.uploadId, task.partNumber, task.partSize, task.file , task.start)
                      .then(function(res) {
                          ++state.loaded;
                          callback(null, res);
                      })
                      .catch(function(err) {
                          callback(err);
                      });
              };
          }

          取消分块上传事件

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

          client.abortMultipartUpload(<BucketName>, <Objectkey>, <UploadID>);

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

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

          client.listMultipartUploads(<bucketName>)
              .then(function (response) {
                  // 遍历所有上传事件
                  for (var i = 0; i < response.body.multipartUploads.length; i++) {
                      console.log(response.body.multipartUploads[i].uploadId);
                  }
              });

          获取所有已上传的块信息

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

          client.listParts(<bucketName>, <key>, <uploadId>)
              .then(function (response) {
                  // 遍历所有上传事件
                  for (var i = 0; i < response.body.parts.length; i++) {
                      console.log(response.body.parts[i].partNumber);
                  }
              });
          上一篇
          Bucket管理
          下一篇
          版本变更记录