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

时间:2014-09-10 03:04:00

标签: java file-upload amazon-web-services amazon-s3 image-uploading

我正在尝试开发一个上传管理器(可在您的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();
    }
    }
    }
    
  3. 我很欣赏使用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
    

3 个答案:

答案 0 :(得分:2)

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

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

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

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

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

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

答案 1 :(得分:0)

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

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

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

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

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

答案 2 :(得分:0)

问题似乎是基于C#代码的,即使我们用Java实现此问题,我认为这是同一件事,也就是说,按照相同的思想,您可以使用允许的任何语言来构建它,这是关于概念,而不是语法或语言的功能。

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

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

  • )桶的名称
  • )对象键的确切名称(文件名)必须相同
  • UploadId )已停止/崩溃的上载ID
  • 文件)恢复上传的本地文件(仅提及)
  • partSize )大小要上传的字节块(从技术上讲,不必遵循以前使用的相同块大小,         只需确保从正确的字节开始,即已成功上传最后一个字节之后的字节)
  • startFilePosition )就是恢复上载的文件字节位置,必须是最后一个成功上载之前的字节之后
  • 列出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)

在我们的情况下,效果很好。

干杯!