【问题标题】:Confusion on file uploading S3文件上传 S3 的困惑
【发布时间】:2019-11-29 12:46:40
【问题描述】:

我正在将文件保存在我的 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 找到 this post,我明白了我必须定义文件所在的路径来自我的客户的将被保存以供以后上传,就像在这种情况下到亚马逊 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 将部署在哪台机器上?谢谢

【问题讨论】:

标签: java amazon-s3 file-upload


【解决方案1】:

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

当您想将文件上传到系统中时,请尽可能将其作为字节流保存,因为您会在入口处接收字节,并且希望在最后存储这些相同的字节。转换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)

最后一个参数是File。你看到不匹配了吗? 在您第一个让您烦恼的代码中,您通过writing the content of the UploadedFile into a new File 解决了问题(传递File 而您有UploadedFile 作为源),如果您需要File,这是可以接受的。
但实际上您不需要 File,因为 PutObjectRequest() 构造函数有另一个 overload 更适合您的使用:

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));

【讨论】:

  • 是的,它尽可能简单,谢谢:)
  • 简单往往是遵循的方式。欢迎你:)
猜你喜欢
  • 2014-12-01
  • 2021-06-04
  • 2011-05-03
  • 2016-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多