Object管理
上传Object
最简单的上传
-
基本流程
- 创建BosClient。
- 调用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-
开头。
获取上传进度
JavaScript SDK支持在上传过程中实时提供上传进度信息,可通过监听process事件获取相关信息,所有上传相关接口均支持该功能。
-
示例代码:以putObjectFromBlob接口为例
// 以blob对象形式上传,仅支持浏览器环境 client.putObjectFromBlob(bucket, object, <blob对象>) .then(done) .catch(fail); client.on('progress', function() { // do something })
查看Bucket中的Object
简单查询
查看Bucket中Object列表。
-
基本流程
- 创建BosClient。
- 执行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>
)的存储系统,所以原则上并不会存在“文件夹”的概念,但您可以通过 delimiter
和 prefix
参数的配合进行文件夹功能模拟。
假设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
查看模拟文件夹下的文件和子文件夹
在 Prefix
和 Delimiter
结合的情况下,可以列出模拟文件夹下的文件和子文件夹:
// 设置参数
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.avi
,fun/movie/007.avi
两个文件并没有被列出来,因为它们属于fun
文件夹下的movie
子文件夹下的文件。
获取Object(仅支持Node.js)
简单的获取Object
用户可以通过如下代码将Object读取到一个流中。
-
基本流程
- 创建BosClient。
- 执行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下载到指定路径。
-
基本流程
- 创建BosClient。
- 执行client.getObject( )操作。
- 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
-
基本流程
- 创建BosClient。
- 执行deleteObject()方法。
-
示例代码
// 删除Object //指定要删除的Object所在Bucket名称和该Object名称 client.deleteObject(<BucketName>, <ObjectKey>);
-
完整示例
- 浏览器端:
let BosClient = baidubce.sdk.BosClient
- Node.js:
import {BosClient} from '@baiducloud/sdk'
let config = { endpoint: 'https://bj.bcebos.com' //需要根据bucket所属区域进行修改 credentials: { ak: <AccessKeyID>, //您的AK sk: <SecretAccessKey> //您的SK } }; let client = new BosClient(config); client.deleteObject(<BucketName>, <ObjectKey>);
- 浏览器端:
拷贝Object
简单拷贝Object
-
基本流程
- 创建BosClient。
- 执行copyObject( )方法。
-
示例代码
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信息 } //SrcBucketName, SrcKey为原地址,DestBucketName, DestKey为拷贝到的目的地址 client.copyObject(<SrcBucketName>, <SrcKey>, <DestBucketName>, <DestKey>, options);
Object设置meta信息
可以通过拷贝Object的方式设置meta信息。
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);
}
});