[英]Edit pdf file in AWS S3 bucket using iText
AWS S3存储桶具有1个pdf文件。 该pdf文件的内容需要使用iText Java库进行编辑。 修改后的文件需要再次存储在S3存储桶中。 当前,我们正在使用AWS Lambda函数。 在目标s3存储桶中创建空pdf文件,并在AWS cloudWatch中显示错误消息:“管道已关闭”
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();
,该方法不可用stamper.close();
被调用时,您将收到一个异常,因为您不再能够写入inputStream
。
我认为以当前方法解决该问题的任何尝试都无法满足要求,因为在文档中明确指出:
通常,一个线程从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处理。 我建议检查这个文章或搜索使用的通用例子PipedInputStream
用PipedOutputStream
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.