我可以使用Amazon High或Low Level API暂停和恢复分段上传吗?

问题描述 投票:2回答:3

我正在尝试开发一个上传管理器(可在您的PC上安装,不会是一个Web应用程序),它将使用Java将选定的图像文件上传到AmazonS3。现在,我已经完成了编码,它将初始化上传并使用AmazonS3的TransferManager(高级API)暂停上传。问题是,每次我恢复上传,它都从头开始。我已经查看了几个aws博客和aws文档,但这个问题没有直接的答案。我还用低级API编写代码(使用他们的示例代码),但在那里,我不知道如何暂停上传。所以,我的问题是:

  1. 如何从暂停点恢复上传?
  2. 我有两个名为Pause and Resume的按钮(使用JFrames和Swing Worker)。我该怎么办才能反复暂停和恢复?我该如何实现代码? public class UploadObjectMultipartUploadUsingHighLevelAPI { public void pauseUploading(TransferManager tm, Upload upload) throws Exception{ long MB = 1024 * 1024 ; TransferProgress progress = upload.getProgress(); System.out.println("The pause will occur once 5 MB of data is uploaded"); while( progress.getBytesTransferred() < 5*MB ) Thread.sleep(2000); boolean forceCancel = true; float dataTransfered = (float) upload.getProgress().getBytesTransferred(); System.out.println("Data Transfered until now: " + dataTransfered); PauseResult<PersistableUpload> pauseResult = ((Upload) upload).tryPause(forceCancel); System.out.println("The upload has been paused. The code that we've got is " + pauseResult.getPauseStatus()); pauseResult = ((Upload) upload).tryPause(forceCancel); PersistableUpload persistableUpload = (PersistableUpload) pauseResult.getInfoToResume(); System.out.println("Storing information into file"); File f = new File("D:\\Example\\resume-upload"); if( !f.exists() ) f.createNewFile(); FileOutputStream fos = new FileOutputStream(f); persistableUpload.serialize(fos); fos.close(); } public void resumeUploading(TransferManager tm) throws Exception{ FileInputStream fis = new FileInputStream(new File("D:\\Example\\resume-upload")); System.out.println("Reading information from the file"); PersistableUpload persistableUpload; persistableUpload = PersistableTransfer.deserializeFrom(fis); System.out.println("Reading information completed"); System.out.println("The system will resume upload now"); tm.resumeUpload(persistableUpload); fis.close(); // System.out.println("Upload complete."); } public static void main(String[] args) throws Exception { String existingBucketName = "Business.SkySquirrel.RawImages/Test"; String keyName = "Pictures1.zip"; String filePath = "D:\\Pictures1.zip"; TransferManagerConfiguration configuration = new TransferManagerConfiguration(); TransferManager tm = new TransferManager(new ProfileCredentialsProvider()); configuration.setMultipartUploadThreshold(1024 * 1024); tm.setConfiguration(configuration); System.out.println("************* Upload Manager *************"); try { Upload upload = tm.upload(existingBucketName, keyName, new File(filePath)); System.out.println("Upload Started"); System.out.println("Transfer: " + upload.getDescription()); UploadObjectMultipartUploadUsingHighLevelAPI multipartPause = new UploadObjectMultipartUploadUsingHighLevelAPI(); multipartPause.pauseUploading(tm, upload); UploadObjectMultipartUploadUsingHighLevelAPI multipartResume = new UploadObjectMultipartUploadUsingHighLevelAPI(); multipartResume.resumeUploading(tm); } catch (AmazonClientException amazonClientException) { System.out.println("Unable to upload file, upload was aborted."); amazonClientException.printStackTrace(); } } }

我很欣赏使用AmazonS3的高级或低级API的示例代码。

我使用的是SDK的1.8.9.1版。我还在使用以下代码初始化上传,暂停和恢复时添加了进度。

long MB = 1024 * 1024;
    TransferProgress progress = upload.getProgress();
    float dataTransfered = progress.getBytesTransferred();  

    while(!upload.isDone()){
        dataTransfered = progress.getBytesTransferred();
        System.out.println("Data Transfered: " + dataTransfered/MB + " MB");
        Thread.sleep(2000);
    }

我得到以下结果:

密码匹配以下文件被选中:

D:\Pictures3\DSC02247 - Copy.JPG
Writing 'D:\Pictures3\DSC02247 - Copy.JPG' to zip file
D:\Pictures3\DSC02247.JPG
Writing 'D:\Pictures3\DSC02247.JPG' to zip file
D:\Pictures3\DSC02248.JPG
Writing 'D:\Pictures3\DSC02248.JPG' to zip file
************* Upload Manager *************
Upload Started
Transfer: Uploading to *******/****/****.zip
Data Transfered: 0.0 MB
Data Transfered: 0.0703125 MB
Data Transfered: 0.21875 MB
Data Transfered: 0.3203125 MB
Data Transfered: 0.4140625 MB
Data Transfered: 0.515625 MB
....
....
Data Transfered: 0.9609375 MB
Data Transfered: 1.0546875 MB
Pause Commencing
The pause will occur once 5 MB of data is uploaded
Data Transfered: 1.09375 MB
Data Transfered: 1.1640625 MB
Data Transfered: 1.265625 MB
Data Transfered: 1.359375 MB
....
....
Data Transfered: 4.734375 MB
Data Transfered: 4.8359375 MB
Data Transfered: 4.9296875 MB
The upload has been paused. The code that we've got is SUCCESS
Storing information into file
Upload Paused
Resume Commencing
Reading information from the file
Reading information completed
The system will resume upload now
Data Transfered: 0.0 MB
Data Transfered: 0.171875 MB
Data Transfered: 0.265625 MB
Data Transfered: 0.359375 MB
Data Transfered: 0.421875 MB
....
....
Data Transfered: 9.58182 MB
Data Transfered: 9.683382 MB
Data Transfered: 9.753695 MB
Upload Complete
java file-upload amazon-web-services amazon-s3 image-uploading
3个回答
2
投票

使用REST API,这非常简单......只需不再发送任何部分就可以“暂停”,并通过发送下一部分来“恢复”。

“低级API”与REST接口紧密相关,因此功能应该相同。在内部,S3没有“暂停”分段上传的概念。它只是等待 - 无限期 - 让您上传更多部件并完成请求,或者中止请求。它将存储您发送的部件(收取存储费用),直到整个操作完成或中止......它将真正等待几个月(我已经看到它......并且可能会等待它永远等待)为了你“恢复”。

但是没有低级别的暂停/恢复呼叫 - 你只是这样做。

问题是,您必须在本地保留每个部件的etags,并且必须将它们与请求一起发送以完成分段上传。

如果您从未完成或中止多部分操作,则您发送的部件将由S3存储,等待您的下一步操作。

http://docs.aws.amazon.com/AmazonS3/latest/dev/llJavaUploadFile.html


0
投票

您使用的是哪个版本的SDK?

我问的原因是因为在旧版本的SDK中,如果你恢复上传/下载,进度将从恢复点而不是开始点开始,因此总是显示0字节或0%。

您正在使用的TransferManager API应提供恢复/暂停,因此您实际上不需要使用低级API,除非您需要某些功能,而高级API不提供这些功能。

上传可能从一开始就开始的其他原因是因为您在传输块之前暂停,使用加密,或者文件不够大。在你的情况下,我猜这些都不是这种情况,你只是遇到了这个bug。

如果您使用的是最新版本且仍遇到问题,请告诉我们!


0
投票

看起来这个问题是基于C#代码,即使我们用Java实现它,我认为它是同一个东西,也就是说,遵循相同的想法,你可以用它允许的任何语言来构建它,它是关于概念,而不是语法或语言的功能。

在我们的例子中,它不仅要播放/暂停,而且主要是关于在上传60GB文件时可能发生的系统/环境崩溃,因此我们可以从问题发生的最后一点重新开始上传(成功上传最后一个字节后的一个字节),而不是从头开始,这就是重点。

为了实现这一点,我们必须在上传MultiPartUpload文件时跟踪一些信息,如果没有它们,将无法重新启动任何内容。因此,对于每个成功上传的字节块,跟踪(保存)以下信息,我们将需要它们:

  • (桶)桶的名称
  • (键)对象键(文件名)的确切名称必须相同
  • (UploadId)已停止/崩溃的uploadId
  • (文件)恢复上传的本地文件(仅提)
  • (partSize)Size要上传的字节数(从技术上讲,没有必要遵循之前使用的相同块大小,只需要确保从正确的字节开始,即在最后一个字节成功上传后的字节已经)
  • (startFilePosition)这是上传将被恢复的文件的位置(以字节为单位),必须是最后一次成功上传之前的字节
  • (List PartETag)已成功上传PartETag列表(使用PartNumber和eTag信息构建)

必须创建PartETag的集合列表,并填充之前已上载的集合列表。成功上传文件块字节时收到的这些PartETag:

  UploadPartResult uploadResult = s3.uploadPart(uploadRequest);
  partETags.add(uploadResult.getPartETag()); // <-- keep tracked

然后,稍后,我们可以重新创建PartETag列表以重新启动我们停止的位置:

  List<PartETag> partETags = new ArrayList<PartETag>();
  partETags.add(new PartETag(1, "3beb7e9af8674013a48d78ba14b4b075"));
  partETags.add(new PartETag(2, "5bfdc19fa1fa7b7b347f2c13a500d14c"));
  partETags.add(new PartETag(3, "ef18c3c8c4b3162258a35c3bf424bc15"));
  partETags.add(new PartETag(4, "f31091770d8053754a02715dca601fa3"));
  partETags.add(new PartETag(5, "f31aa43f51fba0f8991eb3971a9c55b0"));

掌握了所有这些功能后,我们可以重新启动/恢复上传,在我们停止(或崩溃)的位置之后准确考虑序列和FilePosition(以字节为单位):

  UploadPartRequest uploadRequest = new UploadPartRequest()
                .withBucketName(bucket)
                .withKey(key)
                .withUploadId(initResponse.getUploadId())
                .withPartNumber(sequence) // 
                .withFileOffset(filePosition)
                .withFile(file)
                .withPartSize(partSize);

// sequence = (Last PartNumber Uploaded) + 1 (In the sample here, must be 6)
// filePosition = LastBytePosition Uploaded + (Block Size Bytes)

在我们的例子中,它运作良好。

干杯!

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.