[英]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.