3

我的目标是:

  1. 从 S3 读取文件,
  2. 更改其元数据
  3. 再次将其推送到 S3

AWS java SDK 不允许推送输出流。因此,我必须将outputstreamstep2 转换为inputstream. 为此,我决定使用PipedInputStream.

但是,我的代码只是挂在writeTo(out);步骤中。此代码位于 grails 应用程序中。当代码挂起时,CPU 不处于高消耗状态:

import org.apache.commons.imaging.formats.jpeg.xmp.JpegXmpRewriter;

AmazonS3Client client = nfile.getS3Client() //get S3 client
S3Object object1 = client.getObject(
                  new GetObjectRequest("test-bucket", "myfile.jpg")) //get the object. 

InputStream isNew1 = object1.getObjectContent(); //create input stream
ByteArrayOutputStream os = new ByteArrayOutputStream();
PipedInputStream inpipe = new PipedInputStream();
final PipedOutputStream out = new PipedOutputStream(inpipe);

try {
   String xmpXml = "<x:xmpmeta>" +
    "\n<Lifeshare>" +
    "\n\t<Date>"+"some date"+"</Date>" +
    "\n</Lifeshare>" +
    "\n</x:xmpmeta>";/
   JpegXmpRewriter rewriter = new JpegXmpRewriter();
   rewriter.updateXmpXml(isNew1,os, xmpXml); //This is step2

   try {
new Thread(new Runnable() {
    public void run () {
        try {
            // write the original OutputStream to the PipedOutputStream
            println "starting writeto"
            os.writeTo(out);
            println "ending writeto"
        } catch (IOException e) {
            // logging and exception handling should go here
        }
    }
}).start();

         ObjectMetadata metadata = new ObjectMetadata();
         metadata.setContentLength(1024); //just testing
         client.putObject(new PutObjectRequest("test-bucket", "myfile_copy.jpg", inpipe, metadata));
         os.writeTo(out);

         os.close();
         out.close();
   } catch (IOException e) {
         // logging and exception handling should go here
   }

}
finally {
   isNew1.close()
   os.close()
   out.close()
}

上面的代码只是打印starting writeto和挂起。它不打印ending writeto

更新 通过将文件放在writeTo一个单独的线程中,文件现在被写入 S3,但是,只有 1024 个字节被写入。文件不完整。如何编写从输出流到 S3 的所有内容?

4

2 回答 2

2

当您执行 os.writeTo(out) 时,它会尝试将整个流刷新到out,并且由于没有人从它的另一侧(即 inpipe)读取,内部缓冲区填满并且线程停止。

您必须在写入数据之前设置阅读器,并确保它在单独的线程中执行(请参阅 PipedOutputStream 上的 javadoc)。

于 2016-10-26T19:49:22.050 回答
1

根据 Bharal 的要求,多亏了上面的评论,我自己才解决了这个问题。因此,添加该示例代码。希望它可以帮助某人!

public void doSomething() throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    baos.write("some bytes to stick in the stream".getBytes());

    InputStream inStr = toInputStream(baos);
}

public InputStream toInputStream(ByteArrayOutputStream orgOutStream) throws IOException{
    PipedInputStream in = new PipedInputStream();
    PipedOutputStream out = new PipedOutputStream();

    try{
        new Thread(((Runnable)() -> {
            try{
                orgOutStream.writeTo(out);
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        })).start();
    } finally{
        orgOutStream.close();
    }
    return in;
}

真正的诀窍是确保管道调用在单独的线程中完成。

于 2020-07-10T23:46:24.333 回答