【问题标题】:How to write an S3 object to a file?如何将 S3 对象写入文件?
【发布时间】:2021-06-24 19:29:53
【问题描述】:

将 S3 对象(我拥有密钥)写入文件的最快方法是什么?我正在使用 Java。

【问题讨论】:

    标签: java amazon-web-services file-io amazon-s3


    【解决方案1】:

    Java 7(于 2011 年 7 月发布)以来,有一个更好的方法:来自 java.util.nio.fileFiles.copy() 实用程序。

    将输入流中的所有字节复制到文件中。

    所以你需要 既不需要 an external library 也不需要滚动你自己的byte array loops。下面两个例子,都使用来自S3Object.getObjectContent()的输入流。

    InputStream in = s3Client.getObject("bucketName", "key").getObjectContent();
    

    1) 写入指定路径的新文件:

    Files.copy(in, Paths.get("/my/path/file.jpg"));
    

    2) 写入系统默认 tmp 位置的临时文件:

    File tmp = File.createTempFile("s3test", "");
    Files.copy(in, tmp.toPath(), StandardCopyOption.REPLACE_EXISTING);
    

    (不指定替换现有文件的选项,您将获得FileAlreadyExistsException。)

    另请注意getObjectContent() Javadocs 敦促您关闭输入流

    如果你检索一个 S3Object,你应该关闭这个输入流 尽快,因为对象内容没有被缓冲 内存和流直接来自 Amazon S3。此外,未能关闭 此流可能会导致请求池被阻塞。

    所以最安全的做法应该是把所有东西都包装在 try-catch-finally 中,并在 finally 块中执行 in.close();

    以上假设您使用来自亚马逊的官方 SDK (aws-java-sdk-s3)。

    【讨论】:

    • 这比循环遍历字节的旧方法要好得多。
    • 我宁愿做Files.copy(in, Paths.get("/my/path/file.jpg"))。最好在不通过文件的情况下获取路径
    • 如果你不需要捕捉考虑try with resources
    • @davidvandebunte 即使您需要捕获资源,您也可以将 try 与资源一起使用...请参阅您引用的文档中的这一点:“try-with-resources 语句可以像 catch 和 finally 块一样一个普通的 try 语句”
    【解决方案2】:

    虽然IOUtils.copy()IOUtils.copyLarge() 很棒,但我更喜欢循环输入流直到输入流返回-1 的老式方法。为什么?我之前使用过 IOUtils.copy() 但是有一个特定的用例,如果我开始从 S3 下载一个大文件,然后由于某种原因如果该线程被中断,下载不会停止,它会一直持续到整个文件已下载。

    当然,这与 S3 无关,只是 IOUtils 库。

    所以,我更喜欢这个:

    InputStream in = s3Object.getObjectContent();
    byte[] buf = new byte[1024];
    OutputStream out = new FileOutputStream(file);
    while( (count = in.read(buf)) != -1)
    {
       if( Thread.interrupted() )
       {
           throw new InterruptedException();
       }
       out.write(buf, 0, count);
    }
    out.close();
    in.close();
    

    注意:这也意味着您不需要额外的库

    【讨论】:

    • 文件被gzip了怎么办?
    • 引发索引 OOB 异常。
    • 或者只是按照@Jonik 的回答做Files.copy(in, Paths.get("/my/path/file.jpg"))
    【解决方案3】:

    AmazonS3Client 类有以下方法:

    S3Object getObject(String bucketName, String key)
    

    返回的S3Object有方法...

    java.io.InputStream getObjectContent()
    

    ..它将对象内容作为流获取。我会像这样使用来自 Apache Commons 的 IOUtils:

    IOUtils.copy(s3Object.getObjectContent(), new FileOutputStream(new File(filepath)));

    【讨论】:

    • 文件被gzip压缩了怎么办?
    【解决方案4】:

    这个使用 TransferManager 的班轮怎么样:

    TransferManagerBuilder.defaultTransferManager
      .download("bucket-name", "key", new File("."))
    

    【讨论】:

      【解决方案5】:

      AWS SDK for Java v2 于 2017 年发布,您只需指定 Path 即可写入文件。

      s3.getObject(GetObjectRequest.builder().bucket(bucket).key(key).build(),
              ResponseTransformer.toFile(Paths.get("multiPartKey")));
      

      https://docs.aws.amazon.com/sdk-for-java/v2/developer-guide/examples-s3-objects.html#download-object

      如果需要File,可以使用toFile方法。

      Path path = Paths.get("file.txt");
      s3.getObject(GetObjectRequest.builder().bucket(bucket).key(key).build(),
              path);
      File file = path.toFile();
      

      【讨论】:

        【解决方案6】:
                    byte[] content = IOUtils.toByteArray(myS3Object.getObjectContent());
        
                    // path where to save the file
                    File myFile = new File("/home/ayoub/Android/release.apk");
        
                    //save content to file
                    FileUtils.writeByteArrayToFile(apkFile, content);
        
                    // OPTIONAL if you'd like to return a resource
                    Resource resource = new ByteArrayResource( content );
        

        【讨论】:

          猜你喜欢
          • 2017-03-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-20
          • 2011-09-25
          • 2011-12-11
          • 2021-05-20
          相关资源
          最近更新 更多