使用iText在AWS S3存储桶中编辑pdf文件
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";
}
的问题是不是在AWS或iText的,而是在你处理PipedInputStream
和PipedOutputStream
的方式。
特别是最有价值的数据被写入时stamper.close()
被称为PDF,但在关闭压模之前设定的内容长度meta.setContentLength(inputStream.available());
,因此长度无效。你叫putObject
后,inputStream
实例被关闭(检查内部closedByReader
场),但pdfBytes
保持连接到它和inputStream
后不能写它是封闭的,所以当stamper.close();
被调用时,你会得到一个例外,因为你不能写到inputStream
了。
我不认为任何试图解决当前解决这个问题就足够了,因为在documentation它明确提出
通常情况下,数据是从的PipedInputStream对象由一个线程和数据读取通过其他线程写入相应的PipedOutputStream。 不建议尝试使用来自单个线程的两个对象,因为它可能会使线程发生死锁。
那么一个解决方案是,虽然没有那么高效存储,使用ByteArrayOutputStream
和ByteArrayInputStream
:
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文章或搜索使用PipedInputStream
与PipedOutputStream
的通用示例。