![](/img/trans.png)
[英]AWS Java SDK - using ProgressListener with TransferManager
[英]Using AWS Java S3 SDK TransferManager to resume an upload from a SFTP stream
目前,我正在使用 Java 的 S3 SDK 中的 AWS 的 TransferManager 触发从 SFTP 服务器到 S3 的上传。 我触发此上传的方式如下:
(伪代码...)
@Autowired
TransferManager transferManager;
@Autowired
SftpStreamFactory sftpStreamFactory;
SftpStream sftpStream = sftpStreamFactory.createStream(filePath);
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(sftpStream.getSizeBytes());
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, sftpStream.getStream(), objectMetadata);
putObjectRequest.setGeneralProgressListener(new UploadBeginEndNotificationListener(uploadRequest, statusNotifier));
transferManager.upload(putObjectRequest);
这是SftpStream
的定义:
@AllArgsConstructor
public class SftpStreamFactory {
@Getter
@AllArgsConstructor
public static class SftpStream {
private final long sizeBytes;
private final InputStream stream;
}
private final SftpRemoteFileTemplate sftpTemplate;
private final SftpProperties sftpProperties;
public SftpStream createStream(Path relativePath) {
return sftpTemplate.<SftpStream, ChannelSftp>executeWithClient(session -> createStream(session, relativePath));
}
SftpStream createStream(ChannelSftp channelSftp, Path relativePath) {
String path = sftpProperties.getRoot().resolve(relativePath).toString();
try {
SftpATTRS fileAttrs = channelSftp.lstat(path);
long size = fileAttrs.getSize();
return new SftpStream(size, channelSftp.get(path));
}
catch (SftpException e) {
throw new UncheckedIOException(new NestedIOException("SFTP Error", e));
}
}
}
这种上传方法效果很好。 但是,如果分段上传在中间暂停/取消/以其他方式中止,我们希望从中断的地方继续,而不是重新开始。 我们知道 TransferManagers resumeUpload
方法采用PersistableUpload
。
但是,在PersistableUpload
的 javadoc 中,它期望在构造函数中传递一个file
路径,然后尝试从中创建一个File
对象: https : //docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/ com/amazonaws/services/s3/transfer/PersistableUpload.html
我们想知道的是,有没有办法在没有这个文件对象的情况下恢复上传,而我们无法从ChannelSftp
获得它? 也就是说,我们可以从流而不是文件恢复上传吗? 或者我们是否必须切换到使用低级别 s3 api 来执行这样的简历。 任何建议表示赞赏。
编辑 - 进一步研究,甚至为已经存在的上传传递一个 UploadId,如果没有文件,doUpload 方法将抛出异常。 有任何想法吗?
答案是,不,您不能在没有文件的情况下继续上传,但是对于您的类似情况,有一种解决方法:
#成功暂停前中止
boolean forceCancel = true;
PauseResult<PersistableUpload> pauseResult = myUpload.tryPause(forceCancel);
info to resume
数据info to resume
到文件PersistableUpload persistableUpload = pauseResult.getInfoToResume();
File f = new File("UNIQUE-ID-FOR-UPLOADED-FILE"); //blob
if (!f.exists())
f.createNewFile();
FileOutputStream fos = new FileOutputStream(f);
// Serialize the persistable upload to the file.
persistableUpload.serialize(fos);
fos.close();
TransferManager tm = new TransferManager();
FileInputStream fis = new FileInputStream(new File("UNIQUE-ID-FOR-UPLOADED-FILE"));
// Deserialize PersistableUpload information from disk.
PersistableUpload persistableUpload = PersistableTransfer.deserializeFrom(fis);
// Call resumeUpload with PersistableUpload.
tm.resumeUpload(persistableUpload);
fis.close();
#SAVE 流以维护文件如果发生某些事情(例如 JVM 崩溃)
使用S3SyncProgressListener
到TransferManager#upload
来保存每个更改并将数据序列化到磁盘。
transferManager.upload(putObjectRequest, new S3SyncProgressListener() {
ExecutorService executor = Executors.newFixedThreadPool(1);
@Override
public void onPersistableTransfer(final PersistableTransfer persistableTransfer) {
executor.submit(new Runnable() {
@Override
public void run() {
try {
File f = new File("UNIQUE-ID-FOR-UPLOADED-FILE");
if (!f.exists()) {
f.createNewFile();
}
FileOutputStream fos = new FileOutputStream(f);
persistableTransfer.serialize(fos);
fos.close();
} catch (IOException e) {
throw new RuntimeException("Unable to persist transfer to disk.", e);
}
}
});
}
});
希望能帮助到你。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.