2017-10-17 124 views
0

AWS S3存储桶有1个pdf文件。这个pdf文件的内容需要使用iText Java库进行编辑。修改后的文件需要再次存储在S3存储桶中。目前,我们正在使用AWS Lambda函数。在目的地S3存储桶是越来越创建空的PDF文件与AWS CloudWatch的错误消息:“管道关闭”使用iText在AWS S3存储桶中编辑pdf文件

LAMBDA Java代码:

private String bucketName = "forms-storage"; 

public String getProposalPdf(InputRequest inputRequest, Context context) throws DocumentException, IOException{ 

    final BasicAWSCredentials awsCreds = new BasicAWSCredentials(ConstantValues.AccessKey, ConstantValues.SecretKey); 
    final AmazonS3Client s3client = (AmazonS3Client) AmazonS3ClientBuilder.standard().withRegion(Regions.AP_SOUTH_1) 
        .withCredentials(new AWSStaticCredentialsProvider(awsCreds)).build(); 
    S3Object object = s3client.getObject(new GetObjectRequest(bucketName, "forms/COMBO ver 1.1.pdf")); 
    InputStream objectData = object.getObjectContent(); 

    PdfReader reader; 
    PdfStamper stamper = null; 
    BaseFont bf; 

    PipedOutputStream pdfBytes = new PipedOutputStream(); 

    try {   
     reader = new PdfReader(objectData); 
     stamper = new PdfStamper(reader, pdfBytes); 

     bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED); 

     PdfContentByte over = stamper.getOverContent(1); 
     over.beginText(); 
     over.setColorFill(BaseColor.BLACK); 
     over.setFontAndSize(bf, 12); 
     over.setTextMatrix(120,717); 
     over.showText("this is edited text"); 
     over.endText(); 

     PipedInputStream inputStream = new PipedInputStream(pdfBytes); 

     ObjectMetadata meta = new ObjectMetadata(); 
     meta= object.getObjectMetadata(); 
     meta.setContentLength(inputStream.available());   

     s3client.putObject(new PutObjectRequest(bucketName, "forms/123.pdf", inputStream, meta));   

    } catch (IOException e) { 
     e.printStackTrace(); 
    } catch (DocumentException e) { 
     e.printStackTrace(); 
    } 
    finally 
    { 
     stamper.close();    
     objectData.close(); 
    } 
    return "PDF Created"; 
} 

回答

0

的问题是不是在AWS或iText的,而是在你处理PipedInputStreamPipedOutputStream的方式。

特别是最有价值的数据被写入时stamper.close()被称为PDF,但在关闭压模之前设定的内容长度meta.setContentLength(inputStream.available());,因此长度无效。你叫putObject后,inputStream实例被关闭(检查内部closedByReader场),但pdfBytes保持连接到它和inputStream后不能写它是封闭的,所以当stamper.close();被调用时,你会得到一个例外,因为你不能写到inputStream了。

我不认为任何试图解决当前解决这个问题就足够了,因为在documentation它明确提出

通常情况下,数据是从的PipedInputStream对象由一个线程和数据读取通过其他线程写入相应的PipedOutputStream。 不建议尝试使用来自单个线程的两个对象,因为它可能会使线程发生死锁。

那么一个解决方案是,虽然没有那么高效存储,使用ByteArrayOutputStreamByteArrayInputStream

ByteArrayOutputStream pdfBytes = new ByteArrayOutputStream(); 

try { 
    reader = new PdfReader(objectData); 
    stamper = new PdfStamper(reader, pdfBytes); 

    bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED); 

    PdfContentByte over = stamper.getOverContent(1); 
    over.beginText(); 
    over.setColorFill(BaseColor.BLACK); 
    over.setFontAndSize(bf, 12); 
    over.setTextMatrix(120,717); 
    over.showText("this is edited text"); 
    over.endText(); 

    stamper.close(); 
    objectData.close(); 

    ObjectMetadata meta = new ObjectMetadata(); 
    meta= object.getObjectMetadata(); 
    ByteArrayInputStream inputStream = new ByteArrayInputStream(pdfBytes.toByteArray()); 
    meta.setContentLength(inputStream.available()); 

    s3client.putObject(new PutObjectRequest(bucketName, "forms/123.pdf", inputStream, meta));  

} catch (IOException e) { 
    e.printStackTrace(); 
} catch (DocumentException e) { 
    e.printStackTrace(); 
} 

通常PDF文件的大小没有如此巨大,这样就可以让自己将它们存储在存储器中。如果您想优化内存消耗,您应该在单独的线程中执行PDF处理。我建议检查this文章或搜索使用PipedInputStreamPipedOutputStream的通用示例。

相关问题