首页 > 解决方案 > 文件上传 S3 的困惑

问题描述

我将文件保存在我的 S3 存储桶上,但我注意到为此我使用了FileOutPutStream这样的方法:

private UploadedFile file; // This is from PrimeFaces, the file that the client wishes to upload
File uploadedFile = new File(file.getFileName()); // Leaving the file like this creates the file on my IDE folder AFTER executing the next two lines, thats why I though the next lines were an error.

FileOutputStream fileOutput = new FileOutputStream(uploadedFile);
fileOutput.write(file.getContents());

所以这行代码负责在我的设备上写入文件,我首先认为这是一个错误或者没有必要,因为我对文件上传到亚马逊不太了解,所以我删除了这两行,因为我注意到我的上传方法只需要文件和文件名,如下所示:

businessDelegatorView.uploadPublicRead("mybucketname", fileName, fileToUpload);

所以我虽然这不是必需的,那只是复制文件:

FileOutputStream fileOutput = new FileOutputStream(uploadedFile);
fileOutput.write(file.getContents());

但是我注意到,如果我删除它们,上传将不起作用,因为它会抛出一个FileNotFoundException,所以我开始搜索并从 BalusC 找到这篇文章,我明白了我必须定义一个路径,我的客户的文件将被保存为稍后像在这种情况下一样上传到亚马逊 s3 存储桶,但我想知道,例如,在生成 .WAR 时这样做是否会起作用:

File uplodadFile = new File("C:/xampp/apache/conf", file.getFileName());

FileOutputStream fileOutput = new FileOutputStream(uploadFile);
fileOutput.write(file.getContents());

我将文件保存在那里作为测试,但我不知道或不确定是否FileOutPutStream是正确的选择,我不知道另一种方式。

这也是执行上述代码后上传方法的样子,没有FileOutPutStream它不会工作导致文件不在我的设备中

AmazonS3 amazonS3 = buildAmazonS3(); 
         try {
             amazonS3.putObject(new PutObjectRequest(bucketName, key, file).withCannedAcl(CannedAccessControlList.PublicRead));

只是希望有人为我澄清一些事情,比如在这里放置的最佳路径是什么?

File uplodadFile = new File("C:/xampp/apache/conf", file.getFileName());

或者我只需要记住.WAR将部署在哪台机器上真的没关系?谢谢

标签: javaamazon-s3file-upload

解决方案


只是希望有人为我澄清一些事情,比如在这里放置的最佳路径是什么?

当您想将文件上传到系统中时,请尽可能将其保存为字节流,因为您会在条目中接收字节并且您希望在最后存储这些相同的字节。转换bytes->file->bytes耗时、消耗资源且容易出错(编码转换和存储在文件系统上的文件可能确实是错误的来源)。

所以我虽然这不是必需的,那只是复制文件:

FileOutputStream fileOutput = new FileOutputStream(uploadedFile); fileOutput.write(file.getContents());

您是对的,因为该文件已由客户端 HTTP 请求上传。
做两次看起来很无奈。
但是你没有File一个UploadedFile(primefaces)

S3 API的PutObjectRequest()构造函数有几个重载。
实际上你使用它:

public PutObjectRequest(String bucketName,
                        String key,
                        File file)

最后一个参数是 a File。你看到不匹配了吗?在您第一个让您烦恼的代码FileUploadedFile通过UploadedFileFileFile.
但实际上您不需要 File 因为PutObjectRequest()构造函数有另一个更适合您使用的重载:

public PutObjectRequest(String bucketName,
                        String key,
                        InputStream input,
                        ObjectMetadata metadata)

构造一个新的 PutObjectRequest 对象以将数据流上传到指定的存储桶和键。构建请求后,用户还可以选择指定对象元数据或标准 ACL。

请注意,为了不损害性能,提供内容长度很重要:

数据流的内容长度必须在对象元数据参数中指定;Amazon S3 要求在上传数据之前将其传入。未能指定内容长度将导致输入流的全部内容在内存中本地缓冲,以便可以计算内容长度,这可能会导致负面的性能问题。

所以你可以这样做:

UploadedFile file = ...; // uploaded by client
ObjectMetadata metaData = new ObjectMetadata();
metaData.setContentLength(file.getSize());
amazonS3.putObject(new PutObjectRequest(bucketName, key, file.getInputStream(), metaData)
        .withCannedAcl(CannedAccessControlList.PublicRead));

推荐阅读