如何在计算 MD5 和文件大小时有效地流式传输大文件?

How do I effectively Stream large files while calculating MD5 and file size?

提问人:TheStranger 提问时间:9/15/2023 最后编辑:TheStranger 更新时间:9/15/2023 访问量:28

问:

我有一个服务,我从客户端服务器接收文件,然后我应该将文件上传到我的 Cloudflare 目录。据我了解,这里有 2 条流。一个是从客户端到服务,另一个是从服务到 Cloudflare。

应该可以上传最大 15 GB 的文件,为了支持它并避免内存过载,我想以小块形式流式传输文件,而不是一次上传完整文件。这适用于两个流(客户端 -> 服务和服务 -> Cloudflare)。

因此,当我流式传输文件时,我想逐块计算 MD5 和文件大小。

这是我到目前为止尝试过的:

我有这个类:AwsConfig

@Configuration
public class AwsConfig {

    @Value("***********")
    private String accessKey;
    @Value("***********")
    private String secretKey;
    @Value("***********")
    private String endpoint;

    @Bean
    public AmazonS3 amazonS3() {
        if (Strings.isNullOrEmpty(endpoint)) throw new RuntimeException("needs s3 endpoint");
        // remove trailing slash
        var s3Url = endpoint.replaceAll("/$", "");

        var credentials = new BasicAWSCredentials(accessKey, secretKey);
        var clientConfiguration = new ClientConfiguration();
        //clientConfiguration.setSignerOverride("AWSS3V4SignerType");
        var endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(s3Url, "auto");
        return AmazonS3ClientBuilder
                .standard()
                .withEndpointConfiguration(endpointConfiguration)
                .withPathStyleAccessEnabled(true)
                .withClientConfiguration(clientConfiguration)
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .build();
    }

    @Bean
    public TransferManager transferManager(AmazonS3 amazonS3) {
        TransferManagerBuilder builder = TransferManagerBuilder.standard()
                .withS3Client(amazonS3)
                .withMultipartUploadThreshold(50L * 1024 * 1024)  // Start multipart upload for files over 50MB
                .withExecutorFactory(() -> Executors.newFixedThreadPool(10));  // Limit the thread pool size

        return builder.build();
    }
}

然后,我有这个端点,它从客户端接收文件并将其流式传输到 Cloudflare:

@PostMapping("/file/upload")
@Operation(summary = "upload file")
public ResponseEntity<?> uploadFile(@RequestPart("file") MultipartFile file,
                                    @RequestPart("data") UploadUrl url) {
    try {
        if (file.isEmpty()) {
            return ResponseEntity.badRequest().body("File is empty");
        }

        String uploadUrl = url.getUrl();

        String[] uploadUrlSplit = uploadUrl.split("/");
        String bucket = uploadUrlSplit[0];
        String packageFileURL = String.join("/", Arrays.copyOfRange(uploadUrlSplit, 1, uploadUrlSplit.length));

        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(file.getSize());

        // Use TransferManager to upload the file
        Upload upload = transferManager.upload(bucket, packageFileURL, file.getInputStream(), metadata);

        upload.waitForCompletion(); // Wait for the upload to complete

        return ResponseEntity.ok().body("File uploaded successfully");
    } catch (Exception e) {
        return ResponseEntity.internalServerError().body("Upload failed: " + e.getMessage());
    }
}

这可以打开和关闭,上传 20 GB 文件需要 25-10 分钟。有时它会超时,我无法弄清楚如何在不缓冲整个文件的情况下进行 MD5 和文件大小计算。

我尝试使用,但我没有设法让它工作。如果我删除这一行,那么它可以在不到 15 分钟的时间内上传一个 2 GB 的文件,内存飙升。.TeeInputStreamupload.waitForCompletion(); // Wait for the upload to complete

我希望它的工作方式是首先确保文件流式传输到上传服务器的速度与上传到 Cloudflare S3 的速度一样快,这是为了确保客户端可以显示上传距离的准确数字。

其次,我想将流克隆成两个流(我可以为此使用 TeeInputStream),其中一个流上传,另一个流使用输入流摘要计算 MD5,因此我不必在内存中存储任何内容。

请问,我该如何解决这个问题?

amazon-s3 输入流 MD5 awss3transfermanager s3transfermanager

评论


答: 暂无答案