1.目标

在上一篇文章中 ,我们研究了如何使用jclouds中的通用Blob API将内容上传到S3。 在本文中,我们将使用jcloudsS3特定的异步API上传内容并利用S3提供的分段上传功能。

2.准备

2.1。 设置自定义API

上传过程的第一部分是创建jclouds API-这是针对Amazon S3的自定义API:

public AWSS3AsyncClient s3AsyncClient() {String identity = ...String credentials = ...BlobStoreContext context = ContextBuilder.newBuilder('aws-s3').credentials(identity, credentials).buildView(BlobStoreContext.class);RestContext<AWSS3Client, AWSS3AsyncClient> providerContext = context.unwrap();return providerContext.getAsyncApi();
}

2.2。 确定内容的零件数

Amazon S3对于要上传的每个部分都有5 MB的限制。 因此,我们需要做的第一件事就是确定可以分割内容的适当数量的部分,以使我们没有低于5 MB限制的部分:

public static int getMaximumNumberOfParts(byte[] byteArray) {int numberOfParts= byteArray.length / fiveMB; // 5*1024*1024if (numberOfParts== 0) {return 1;}return numberOfParts;
}

2.3。 将内容分成几部分

将把字节数组分成一定数量的部分:

public static List<byte[]> breakByteArrayIntoParts(byte[] byteArray, int maxNumberOfParts) {List<byte[]> parts = Lists.<byte[]> newArrayListWithCapacity(maxNumberOfParts);int fullSize = byteArray.length;long dimensionOfPart = fullSize / maxNumberOfParts;for (int i = 0; i < maxNumberOfParts; i++) {int previousSplitPoint = (int) (dimensionOfPart * i);int splitPoint = (int) (dimensionOfPart * (i + 1));if (i == (maxNumberOfParts - 1)) {splitPoint = fullSize;}byte[] partBytes = Arrays.copyOfRange(byteArray, previousSplitPoint, splitPoint);parts.add(partBytes);}return parts;
}

我们将测试将字节数组分成多个部分的逻辑–我们将生成一些字节,将字节数组拆分,使用Guava将其重新组合在一起,并验证是否可以获取原始字节:

@Test
public void given16MByteArray_whenFileBytesAreSplitInto3_thenTheSplitIsCorrect() {byte[] byteArray = randomByteData(16);int maximumNumberOfParts = S3Util.getMaximumNumberOfParts(byteArray);List<byte[]> fileParts = S3Util.breakByteArrayIntoParts(byteArray, maximumNumberOfParts);assertThat(fileParts.get(0).length + fileParts.get(1).length + fileParts.get(2).length,equalTo(byteArray.length));byte[] unmultiplexed = Bytes.concat(fileParts.get(0), fileParts.get(1), fileParts.get(2));assertThat(byteArray, equalTo(unmultiplexed));
}

要生成数据,我们只需使用Random的支持:

byte[] randomByteData(int mb) {byte[] randomBytes = new byte[mb * 1024 * 1024];new Random().nextBytes(randomBytes);return randomBytes;
}

2.4。 创建有效载荷

既然我们已经为内容确定了正确的部分数量,并且设法将内容分解为多个部分,那么我们需要为jclouds API 生成Payload对象

public static List<Payload> createPayloadsOutOfParts(Iterable<byte[]> fileParts) {List<Payload> payloads = Lists.newArrayList();for (byte[] filePart : fileParts) {byte[] partMd5Bytes = Hashing.md5().hashBytes(filePart).asBytes();Payload partPayload = Payloads.newByteArrayPayload(filePart);partPayload.getContentMetadata().setContentLength((long) filePart.length);partPayload.getContentMetadata().setContentMD5(partMd5Bytes);payloads.add(partPayload);}return payloads;
}

3.上载

上传过程是一个灵活的多步骤过程–这意味着:

  • 可以在拥有所有数据之前开始上载–可以在输入数据时上载数据
  • 数据分上传-如果这些操作之一失败,则可以简单地将其检索
  • 块可以并行上传–这可以大大提高上传速度,尤其是在大文件的情况下

3.1。 启动上传操作

上传操作的第一步是启动该过程 。 对S3的请求必须包含标准的HTTP标头–特别是内容MD5标头。 我们将在这里使用Guava哈希函数支持:

Hashing.md5().hashBytes(byteArray).asBytes();

这是整个字节数组(而不是各个部分)的md5哈希

为了启动上载以及与S3的所有进一步交互,我们将使用AWSS3AsyncClient –我们之前创建的异步API:

ObjectMetadata metadata = ObjectMetadataBuilder.create().key(key).contentMD5(md5Bytes).build();
String uploadId = s3AsyncApi.initiateMultipartUpload(container, metadata).get();

密钥是分配给对象的句柄–它必须是客户端指定的唯一标识符。

还要注意,即使我们使用的是异步版本的API, 我们也阻止了该操作的结果–这是因为我们需要初始化的结果才能继续前进。

操作的结果是S3返回的上传ID –这将在整个生命周期中识别上传,并将出现在所有后续的上传操作中。

3.2。 上载零件

下一步是上传零件 。 我们的目标是并行发送这些请求,因为上载零件操作代表了大部分上载过程:

List<ListenableFuture<String>> ongoingOperations = Lists.newArrayList();
for (int partNumber = 0; partNumber < filePartsAsByteArrays.size(); partNumber++) {ListenableFuture<String> future = s3AsyncApi.uploadPart(container, key, partNumber + 1, uploadId, payloads.get(partNumber));ongoingOperations.add(future);
}

零件编号必须是连续的,但发送请求的顺序无关紧要。

提交所有上传零件请求后,我们需要等待它们的响应,以便我们可以收集每个零件的单独ETag值:

Function<ListenableFuture<String>, String> getEtagFromOp =new Function<ListenableFuture<String>, String>() {public String apply(ListenableFuture<String> ongoingOperation) {try {return ongoingOperation.get();} catch (InterruptedException | ExecutionException e) {throw new IllegalStateException(e);}}
};
List<String> etagsOfParts = Lists.transform(ongoingOperations, getEtagFromOp);

如果由于某种原因,上载部分操作之一失败, 则可以重试该操作,直到成功为止。 上面的逻辑不包含重试机制,但是建立它应该足够简单。

3.3。 完成上传操作

上传过程的最后一步是完成分段操作 。 S3 API要求以Map的形式上传来自先前零件的响应,现在我们可以轻松地从上面获得的ETag列表中创建这些响应:

Map<Integer, String> parts = Maps.newHashMap();
for (int i = 0; i < etagsOfParts.size(); i++) {parts.put(i + 1, etagsOfParts.get(i));
}

最后,发送完整的请求:

s3AsyncApi.completeMultipartUpload(container, key, uploadId, parts).get();

这将返回完成对象的最终ETag,并完成整个上传过程。

4。结论

在本文中,我们使用自定义S3 jclouds API构建了一个支持多部分的,完全并行的S3上传操作。 此操作可以按原样使用,但是可以通过几种方法进行改进 。 首先,应在上传操作周围添加重试逻辑,以更好地处理故障。 接下来,对于非常大的文件,即使该机制正在并行发送所有上载的多部分请求, 限制机制仍应限制发送的并行请求的数量。 这既可以避免带宽成为瓶颈,又可以确保Amazon本身不会将上传过程标记为超过每秒允许的请求限制– Guava RateLimiter可能非常适合此操作。

参考:来自baeldung博客的JCG合作伙伴 Eugen Paraschiv的jclouds在S3上进行了分段上传 。

翻译自: https://www.javacodegeeks.com/2013/04/multipart-upload-on-s3-with-jclouds.html

使用jclouds在S3上分段上传相关推荐

  1. jclouds_使用jclouds在S3上分段上传

    jclouds 1.目标 在上一篇文章中 ,我们研究了如何使用jclouds中的通用Blob API将内容上传到S3. 在本文中,我们将使用jclouds的S3特定的异步API上传内容并利用S3提供的 ...

  2. aws cli 上传文件到s3命令_使用 AWS CLI 分段上传到 Amazon S3

    如何使用 AWS CLI 将文件分段上传到 Amazon S3? 上次更新时间:2020 年 11 月 10 日 我想将一个大文件作为多个部分或使用分段上传复制到 Amazon Simple Stor ...

  3. Web API之基于H5客户端分段上传大文件

    http://www.cnblogs.com/OneDirection/articles/7285739.html 查询很多资料没有遇到合适的,对于MultipartFormDataStreamPro ...

  4. Python实现向s3共享存储上传和下载文件

    Python实现向s3共享存储上传和下载文件 https://www.cnblogs.com/liang545621/p/10298617.html 使用Python从S3上传和下载文件 https: ...

  5. vue+videojs视频播放、视频切换、视频断点分段上传

    "本次需求是做一个视频列表,点击视频列表播放对应视频:同时要求实现断点分段上传大文件(视频)的功能 . videojs文档:Getting Started with Video.js - V ...

  6. php - 基于 webuploader 视频大文件分片分段上传,支持断点续传(刷新、关闭页面、重新上传、网络中断等情况)带进度条,前端后端都有示例源码详细教程

    效果图 文件上传前先检测该文件是否已上传,如果已上传提示 "文件已存在",如果未上传则直接上传. 基于 php+webuploader的大文件分片上传,带进度条,支持断点续传(刷新 ...

  7. 如何删除一个CSDN上自己上传的资源

    如何删除一个CSDN上自己上传的资源 第一步,找到你想删除的资源,其URL举例为: http://download.csdn.net/detail/ssergsw/9733040 则删除的get请求为 ...

  8. 怎么才能让计算机发出音乐,我要怎样把电脑上的歌曲传到手机里去啊?-怎么能把电脑里面的歌...

    我要怎样把电脑上的歌曲传到手机里去啊? 追问:电脑的蓝牙??哪? 补充:您的电脑带不带蓝牙,如果不带,就不能用蓝牙传输,您明白吗? 补充:楼主您把您的qq给我跟您讲可以吗? 追问:596364414 ...

  9. 以命令方式从ftp服务器上下载和上传文件

    ** 以命令方式从ftp服务器上下载和上传文件 wang ** 1."开始"→"运行",输入"cmd",打开命令提示符: 2.在命令提示符内 ...

最新文章

  1. 《精通Nginx》——2.3 使用include文件
  2. 白话Elasticsearch55-数据建模之对每个用户发表的博客进行分组 (Top Hits Aggregation)
  3. (59)逆向分析 KiSwapContext 和 SwapContext —— 线程切换核心代码
  4. AFN post的数据编码格式问题
  5. CIO们对数据中心虚拟化心存的六大疑虑
  6. LR运行9415商品拒绝问题
  7. 从零开始学Pytorch(十)之循环神经网络基础
  8. Codeforces Round #629 (Div. 3) A~C
  9. 使用DevExpress.XtraTabbedMdi.XtraTabbedMdiManager控件来加载MDI窗体
  10. Atitit mybatis快速开发 的sql api接口
  11. 数字电子技术之逻辑门电路
  12. IDEA debug提示Connected to the target VM, address: ‘127.0.0.1:xxxxx‘, transport: ‘socket‘的原因
  13. 步进电机基础(5.9)-步进电机的驱动与控制-三相步进电机的驱动电路
  14. JavaScript 模板引擎
  15. 卖衣服有什么引流产品?微商卖衣服引流推广?
  16. 新浪微博上市好故事难讲
  17. 曾经最好用的浏览器凉了?正在被大批网站抛弃
  18. 您的云,您做主:Google Distributed Cloud Hosted 全面可用
  19. empty()与isEmpty(),空判断
  20. python制作一个密码簿_[python]制作密码薄,完成增删改查和文件存储功能。

热门文章

  1. 工业利用计算机实现生产自动化属于,自动化考试试题(含答案)
  2. http响应状态码列表
  3. 实现滚到div时淡入效果
  4. Flex布局 让你的布局更完美
  5. spring react_使用Spring Cloud Gateway保护React式微服务
  6. 纹理和基元_Java的精妙之处,包括基元和变量参数数组
  7. java登录界面命令_Java命令行界面(第18部分):JCLAP
  8. jdbc mysql驱动_MySQL JDBC驱动程序如何处理准备好的语句
  9. aix pax_通过Pax考试对JBoss Fuse 6.x进行集成测试,第一部分
  10. Java 8和Java 14之间的新功能