本文介绍如何下载文件。

简单下载

下载文件,可以指定下载为本地文件,或者下载为NSData:

OSSGetObjectRequest * request = [OSSGetObjectRequest new];

// 必填字段
request.bucketName = @"<bucketName>";
request.objectKey = @"<objectKey>";

// 可选字段
request.downloadProgress = ^(int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
    // 当前下载段长度、当前已经下载总长度、一共需要下载的总长度
    NSLog(@"%lld, %lld, %lld", bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
};
// request.range = [[OSSRange alloc] initWithStart:0 withEnd:99]; // bytes=0-99,指定范围下载
// request.downloadToFileURL = [NSURL fileURLWithPath:@"<filepath>"]; // 如果需要直接下载到文件,需要指明目标文件地址

OSSTask * getTask = [client getObject:request];

[getTask continueWithBlock:^id(OSSTask *task) {
    if (!task.error) {
        NSLog(@"download object success!");
        OSSGetObjectResult * getResult = task.result;
        NSLog(@"download result: %@", getResult.dowloadedData);
    } else {
        NSLog(@"download object failed, error: %@" ,task.error);
    }
    return nil;
}];

// [getTask waitUntilFinished];

// [request cancel];

图片处理

OSS图片处理是OSS对外提供的海量、安全、低成本、高可靠的图片处理服务。 用户将原始图片上传保存到OSS,通过简单的 RESTful 接口,在任何时间、任何地点、任何互联网设备上对图片进行处理。 图片处理提供图片处理接口,图片上传请使用上传接口。基于OSS图片处理,用户可以搭建自己的图片处理服务。

图片处理的详细信息请参见OSS图片处理指南

OSS图片处理提供以下功能:

SDK中使用时,只需要在下载图片时,调用request.setxOssProcess()方法设置处理参数。示例:

OSSGetObjectRequest * request = [OSSGetObjectRequest new];
request.bucketName = @"<bucketName>";
request.objectKey = @"example.jpg";
// 图片处理
request.xOssProcess = @"image/resize,m_lfit,w_100,h_100";
OSSTask * getTask = [client getObject:request];
[getTask continueWithBlock:^id(OSSTask *task) {
    if (!task.error) {
        NSLog(@"download image success!");
        OSSGetObjectResult * getResult = task.result;
        NSLog(@"download image data: %@", getResult.dowloadedData);
    } else {
        NSLog(@"download object failed, error: %@" ,task.error);
    }
    return nil;
}];
// [getTask waitUntilFinished];
// [request cancel];

需要对图片进行其它处理,只要替换request.setxOssProcess()的参数就可以了。需要帮助,请参考:

  • 可视化图片处理工具 ImageStyleViever ,可以直观的看到OSS图片处理的结果
  • OSS图片处理的功能、使用演示 页面

流式下载

实际上,SDK没有提供stream类型的下载接口,但是提供了类似NSURLSession库的didRecieveData的分段回调功能,下载时,每次得到一段数据,会回调这个函数进行通知。注意,如果设置了这个回调,下载的结果将不再包含实际数据。

OSSGetObjectRequest * request = [OSSGetObjectRequest new];
// required
request.bucketName = @"<bucketName>";
request.objectKey = @"<objectKey>";
// 分段回调函数
request.onRecieveData = ^(NSData * data) {
    NSLog(@"Recieve data, length: %ld", [data length]);
};
OSSTask * getTask = [client getObject:request];
[getTask continueWithBlock:^id(OSSTask *task) {
    if (!task.error) {
        NSLog(@"download object success!");
    } else {
        NSLog(@"download object failed, error: %@" ,task.error);
    }
    return nil;
}];
// [getTask waitUntilFinished];
// [request cancel];

指定范围下载

您可以在下载文件时指定一段范围,对于较大的Object适于使用此功能;如果在请求头中使用Range参数,则返回消息中会包含整个文件的长度和此次返回的范围。

OSSGetObjectRequest * request = [OSSGetObjectRequest new];
request.bucketName = @"<bucketName>;
request.objectKey = @"<objectKey>";
request.range = [[OSSRange alloc] initWithStart:1 withEnd:99]; // bytes=1-99
// request.range = [[OSSRange alloc] initWithStart:-1 withEnd:99]; // bytes=-99
// request.range = [[OSSRange alloc] initWithStart:10 withEnd:-1]; // bytes=10-
request.downloadProgress = ^(int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
    NSLog(@"%lld, %lld, %lld", bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
};
OSSTask * getTask = [client getObject:request];
[getTask continueWithBlock:^id(OSSTask *task) {
    if (!task.error) {
        NSLog(@"download object success!");
        OSSGetObjectResult * getResult = task.result;
        NSLog(@"download result: %@", getResult.dowloadedData);
    } else {
        NSLog(@"download object failed, error: %@" ,task.error);
    }
    return nil;
}];
// [getTask waitUntilFinished];
// [request cancel];

只获取文件元信息

通过headObject方法可以只获文件元信息而不获取文件的实体。代码如下:

OSSHeadObjectRequest * request = [OSSHeadObjectRequest new];
request.bucketName = @"<bucketName>;
request.objectKey = @"<objectKey>";

OSSTask * headTask = [client headObject:request];

[headTask continueWithBlock:^id(OSSTask *task) {
    if (!task.error) {
        NSLog(@"head object success!");
        OSSHeadObjectResult * result = task.result;
        NSLog(@"header fields: %@", result.httpResponseHeaderFields);
        for (NSString * key in result.objectMeta) {
            NSLog(@"ObjectMeta: %@ - %@", key, [result.objectMeta objectForKey:key]);
        }
    } else {
        NSLog(@"head object failed, error: %@" ,task.error);
    }
    return nil;
}];

数据完整性校验

因为移动端网络环境的复杂性,数据在客户端和服务器之间传输时有可能会出错。因此OSS SDK在下载过程中提供了基于CRC的端到端的数据完整性效验功能。

CRC校验在读取下载过程中时候,如果开启了crc效验,并有在传输中有数据错误的情况。会提示OSSClientErrorCodeInvalidCRC的错误。

OSSGetObjectRequest * request = [OSSGetObjectRequest new];
request.bucketName = ...;
//开启crc效验
request.crcFlag = OSSRequestCRCOpen;

OSSTask * task = [testProxyClient getObject:request];

[[task continueWithBlock:^id(OSSTask *task) {
	//如果开启了crc效验,并有在传输中有数据错误的情况。会提示OSSClientErrorCodeInvalidCRC的错误
    XCTAssertNil(task.error);
    return nil;
}] waitUntilFinished];

注:如果设置onReceiveData block。开启CRC效验后,需要自行比较CRC数值是否一致。范例如下
OSSGetObjectRequest * request = [OSSGetObjectRequest new];
request.bucketName = ....
request.crcFlag = OSSRequestCRCOpen;
....
    
__block uint64_t localCrc64 = 0;
	//如果设置onReceiveData block
NSMutableData *receivedData = [NSMutableData data];
request.onRecieveData = ^(NSData *data) {
	if (data)
	{
		NSMutableData *mutableData = [data mutableCopy];
    	void *bytes = mutableData.mutableBytes;
    	localCrc64 = [OSSUtil crc64ecma:localCrc64 buffer:bytes length:data.length];
    	[receivedData appendData:data];
    }
};
    
__block uint64_t remoteCrc64 = 0;
OSSTask * task = [_client getObject:request];
[[task continueWithBlock:^id(OSSTask *task) {
	XCTAssertNil(task.error);
   	OSSGetObjectResult *result = task.result;
    if (result.remoteCRC64ecma) 
	{
    	NSScanner *scanner = [NSScanner scannerWithString:result.remoteCRC64ecma];
		[scanner scanUnsignedLongLong:&remoteCrc64];
        if (remoteCrc64 == localCrc64)
        {
        	NSLog(@"crc64校验成功!");
        }
		else
        {
        	NSLog(@"crc64校验失败!");
        }
   }
   return nil;
}] waitUntilFinished];