全部产品
Search
文档中心

对象存储 OSS:iOS禁止覆盖同名文件

更新时间:Dec 20, 2023

默认情况下,如果新添加文件(Object)与现有文件同名且对该文件有访问权限,则新添加的文件将覆盖原有的文件。本文介绍如何通过设置请求头x-oss-forbid-overwrite在简单上传、拷贝文件及分片上传等场景中禁止覆盖同名文件。

简单上传

以下代码用于简单上传时禁止覆盖同名文件:

OSSPutObjectRequest * put = [OSSPutObjectRequest new];

// 填写Bucket名称,例如examplebucket。关于Bucket名称命名规范的更多信息,请参见Bucket。
put.bucketName = @"examplebucket";
// 填写不包含Bucket名称在内的Object完整路径,例如exampledir/exampleobject.txt。关于Object名称命名规范的更多信息,请参见Object。
put.objectKey = @"exampledir/exampleobject.txt";
// 填写待上传的本地文件所在的完整路径。
put.uploadingFileURL = [NSURL fileURLWithPath:@"/storage/emulated/0/oss/examplefile.txt"];

// 指定上传文件操作时是否覆盖同名Object。
// 不指定x-oss-forbid-overwrite时,默认覆盖同名Object。
// 指定x-oss-forbid-overwrite为false时,表示允许覆盖同名Object。
// 指定x-oss-forbid-overwrite为true时,表示禁止覆盖同名Object,如果同名Object已存在,程序将报错。
put.objectMeta = @{@"x-oss-forbid-overwrite": @"true"};

// (可选)设置上传进度。
put.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
    // 指定当前上传长度、当前已上传总长度以及待上传的总长度。
    NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
};
OSSTask * putTask = [client putObject:put];
[putTask continueWithBlock:^id(OSSTask *task) {
    if (!task.error) {
        NSLog(@"upload object success!");
    } else {
        NSLog(@"upload object failed, error: %@" , task.error);
    }
    return nil;
}];

拷贝文件

以下代码用于拷贝文件时禁止覆盖同名文件:

OSSCopyObjectRequest * copy = [OSSCopyObjectRequest new];
// 填写源Bucket名称。
copy.sourceBucketName = @"srcbucket";
// 填写源Bucket内的Object完整路径。
copy.sourceObjectKey = @"dir1/srcobject.txt";
// 填写目标Bucket名称。
copy.bucketName = @"destbucket";
// 填写目标Bucket内的Object完整路径。
copy.objectKey = @"dir2/destobject.txt";

// 指定上传文件操作时是否覆盖同名Object。
// 不指定x-oss-forbid-overwrite时,默认覆盖同名Object。
// 指定x-oss-forbid-overwrite为false时,表示允许覆盖同名Object。
// 指定x-oss-forbid-overwrite为true时,表示禁止覆盖同名Object,如果同名Object已存在,程序将报错。
copy.objectMeta = @{@"x-oss-forbid-overwrite": @"true"};

OSSTask * task = [client copyObject:copy];
[task continueWithBlock:^id(OSSTask *task) {
    if (!task.error) {
        NSLog(@"copy object success!");
    } else {
        NSLog(@"copy object failed, error: %@" , task.error);
    }
    return nil;
}];

分片上传

以下代码用于分片上传时禁止覆盖同名文件:

__block NSString * uploadId = nil;
__block NSMutableArray * partInfos = [NSMutableArray new];
// 填写Bucket名称,例如examplebucket。
NSString * uploadToBucket = @"examplebucket";
// 填写不包含Bucket名称在内的Object完整路径,例如exampledir/exampleobject.txt。
NSString * uploadObjectkey = @"exampledir/exampleobject.txt";
OSSInitMultipartUploadRequest * init = [OSSInitMultipartUploadRequest new];
init.bucketName = uploadToBucket;
init.objectKey = uploadObjectkey;

// 指定上传文件操作时是否覆盖同名Object。
// 不指定x-oss-forbid-overwrite时,默认覆盖同名Object。
// 指定x-oss-forbid-overwrite为false时,表示允许覆盖同名Object。
// 指定x-oss-forbid-overwrite为true时,表示禁止覆盖同名Object,如果同名Object已存在,程序将报错。
init.objectMeta = @{@"x-oss-forbid-overwrite": @"true"};
// multipartUploadInit返回的结果中包含UploadId,UploadId是分片上传的唯一标识。您可以根据该uploadId发起相关操作,例如取消分片上传、查询分片上传等。
OSSTask * initTask = [client multipartUploadInit:init];
[initTask waitUntilFinished];
if (!initTask.error) {
    OSSInitMultipartUploadResult * result = initTask.result;
    uploadId = result.uploadId;
} else {
    NSLog(@"multipart upload failed, error: %@", initTask.error);
    return;
}

// 填写待上传的本地文件所在的完整路径。
NSString * filePath = @"/storage/emulated/0/oss/examplefile.txt";
// 获取待上传文件的大小。
uint64_t fileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil] fileSize];
// 设置分片号,从1开始标识。每一个上传的Part都有一个分片号,取值范围是1~10000。
int chuckCount = *;
// 设置分片大小,单位为字节,取值范围为100 KB~5 GB。
uint64_t offset = fileSize/chuckCount;
for (int i = 1; i <= chuckCount; i++) {
    OSSUploadPartRequest * uploadPart = [OSSUploadPartRequest new];
    uploadPart.bucketName = uploadToBucket;
    uploadPart.objectkey = uploadObjectkey;
    uploadPart.uploadId = uploadId;
    uploadPart.partNumber = i; // part number start from 1

    NSFileHandle* readHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
    [readHandle seekToFileOffset:offset * (i -1)];

    NSData* data = [readHandle readDataOfLength:offset];
    uploadPart.uploadPartData = data;

    OSSTask * uploadPartTask = [client uploadPart:uploadPart];

    [uploadPartTask waitUntilFinished];

    if (!uploadPartTask.error) {
        OSSUploadPartResult * result = uploadPartTask.result;
        uint64_t fileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:uploadPart.uploadPartFileURL.absoluteString error:nil] fileSize];
        [partInfos addObject:[OSSPartInfo partInfoWithPartNum:i eTag:result.eTag size:fileSize]];
    } else {
        NSLog(@"upload part error: %@", uploadPartTask.error);
        return;
    }
}

OSSCompleteMultipartUploadRequest * complete = [OSSCompleteMultipartUploadRequest new];
complete.bucketName = uploadToBucket;
complete.objectKey = uploadObjectkey;
complete.uploadId = uploadId;
complete.partInfos = partInfos;
// 指定完成分片上传操作时是否覆盖同名Object。
// 不指定x-oss-forbid-overwrite时,默认覆盖同名Object。
// 指定x-oss-forbid-overwrite为false时,表示允许覆盖同名Object。
// 指定x-oss-forbid-overwrite为true时,表示禁止覆盖同名Object,如果同名Object已存在,程序将报错。
complete.completeMetaHeader = @{@"x-oss-forbid-overwrite": @"true"};

OSSTask * completeTask = [client completeMultipartUpload:complete];

[[completeTask continueWithBlock:^id(OSSTask *task) {
    if (!task.error) {
        NSLog(@"multipart upload success!");
    } else {
        NSLog(@"multipart upload error: %@", task.error);
    }
    return nil;
}] waitUntilFinished];

相关文档

  • 关于简单上传的API接口说明,请参见PutObject

  • 关于拷贝文件的API接口说明,请参见CopyObject

  • 分片上传的完整实现涉及三个API接口,详情如下: