writeTo PipedOutputStream只是挂起

时间:2016-10-26 19:11:13

标签: java groovy inputstream aws-java-sdk

我的目标是:

  1. 从S3读取文件,
  2. 更改其元数据
  3. 再次推出S3
  4. AWS java SDK不允许推送输出流。因此,我必须将outputstream从第2步转换为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的所有内容?

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

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

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