writeTo PipedOutputStream 只是挂起

writeTo PipedOutputStream just hangs

我的目标是:

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

AWS java SDK 不允许推送输出流。因此,我必须将 outputstream 从 step2 转换为 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?

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

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

根据 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;
}

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