阿里云OSS appendObject 获取 position

阿里云OSS appendObject 获取 position

背景

项目有个需求,每次调用接口,都需要把一行的数据存储到阿里OSS的某个文件去,之后就去翻看 阿里OSS官方文档,发现个追加上传appendObject 的刚好符合需求。

SDK版本

本文例子基于以下SDK JAVA 版本

<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.11.2</version>
</dependency>

官网例子

官网例子

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";

String content1 = "Hello OSS A \n";
String content2 = "Hello OSS B \n";
String content3 = "Hello OSS C \n";

// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ObjectMetadata meta = new ObjectMetadata();
// 指定上传的内容类型。
meta.setContentType("text/plain");

// 通过AppendObjectRequest设置多个参数。
AppendObjectRequest appendObjectRequest = new AppendObjectRequest("<yourBucketName>", "<yourObjectName>", new ByteArrayInputStream(content1.getBytes()),meta);

// 第一次追加。
// 设置文件的追加位置。
appendObjectRequest.setPosition(0L);
AppendObjectResult appendObjectResult = ossClient.appendObject(appendObjectRequest);
// 文件的64位CRC值。此值根据ECMA-182标准计算得出。
System.out.println(appendObjectResult.getObjectCRC());

// 第二次追加。
// nextPosition指明下一次请求中应当提供的Position,即文件当前的长度。
appendObjectRequest.setPosition(appendObjectResult.getNextPosition());
appendObjectRequest.setInputStream(new ByteArrayInputStream(content2.getBytes()));
appendObjectResult = ossClient.appendObject(appendObjectRequest);

// 第三次追加。
appendObjectRequest.setPosition(appendObjectResult.getNextPosition());
appendObjectRequest.setInputStream(new ByteArrayInputStream(content3.getBytes()));
appendObjectResult = ossClient.appendObject(appendObjectRequest);

// 关闭OSSClient。
ossClient.shutdown();
        

问题发现

通过阿里云oss存储追加文件 appendObject类型时,每次 append 都需要指定一个 position 参数,如果position 参数不对,还会报一个 OssExcetion ,内容如下:

image-20201217155558393

那么问题来了,这个position要怎么获取呢?


position获取

1. 同一个请求的多次写入

​ 如果是在同一个方法追加多条,可以通过上一次的执行结果 AppendObjectResult 中的 appendObjectResult.getNextPosition() 方法获取下一次插入的 position 位置。

// 第二次追加。
// nextPosition指明下一次请求中应当提供的Position,即文件当前的长度。
appendObjectRequest.setPosition(appendObjectResult.getNextPosition());
appendObjectRequest.setInputStream(new ByteArrayInputStream(content2.getBytes()));
appendObjectResult = ossClient.appendObject(appendObjectRequest);

2. 两次不同的请求

如果是两次不同的请求,阿里OSS有一个元数据 ObjectMetadata的维护,可以通过 HeadObject 中的

x-oss-next-append-position 获取。

String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String fileName = "<your fileName>";
String bucketName = "your bucketName"
    
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 创建 headObject 请求
HeadObjectRequest request = new HeadObjectRequest(bucketName, fileName);
ObjectMetadata objectMetadata = ossClient.headObject(request);
// 通过反射获取
Field metadataField = ObjectMetadata.class.getDeclaredField("metadata");
metadataField.setAccessible(true);
Map<String, Object> metadata = (Map<String, Object>) metadataField.get(objectMetadata);
String positionStr = (String) metadata.get("x-oss-next-append-position");
long position = Long.parseLong(positionStr);
System.out.println(position);

说明:

  1. x-oss-next-append-position 只有在对于Appendable类型的Object才会返回此Header,指明下一次请求应当提供的position。参考链接:headObject 返回值说明
  2. x-oss-next-append-positionObjectMetadata没有具体的 api 获取 ,存放在ObjectMetadata 中的一个Map 集合中,这个Map属性是一个protected关键字修饰的,不能直接获取。因此需要通过反射获取到 ObjectMetadata 中的 Map 集合,然后通过map.get(“x-oss-next-append-position”) 获取

后记

刚开始获取这个 position 走了不少弯路,主要是没有仔细看过OSS官方文档 ,之前还试过一个在网上看到的说法,可以通过以下的方式获取,结果发现根本不行,时不时还是会报 OssException异常。这才重新去看官方文档找解决方法。

这里也记录下,免得后来者继续采坑

错误的获取方式:

// 判断文件是否存在
boolean exists = ossClient.doesObjectExist(bucketName, fileName);
long position = 0L;
if(exists){
    // 获取文件
    OSSObject cdrObject = ossClient.getObject(bucketName, fileName);
    InputStream objectInputStream = cdrObject.getObjectContent();
    // 直接获取输入流的 available 并不准确,会时不时报错
    position = objectInputStream.available();
}

参考链接

阿里OSS官方文档
appendObject
oss 异常类型
headObject

如果对您有帮助,请帮忙点个赞和收藏!

原创不易,转载请注明出处!

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值