AWS S3存储桶有1个pdf文件。需要使用iText Java库编辑此pdf文件的内容。修改后的文件需要再次存储在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";
}
答案 0 :(得分:0)
问题不在于AWS或iText,而在于您处理PipedInputStream
和PipedOutputStream
的方式。
特别是,大多数有价值的数据在调用stamper.close()
时写入PDF,但在关闭压模之前设置内容长度meta.setContentLength(inputStream.available());
,因此长度无效。致电putObject
后,inputStream
实例已关闭(请检查内部closedByReader
字段),但pdfBytes
仍然与之相关,但在inputStream
之后无法写入stamper.close();
已关闭,因此当调用inputStream
时,您会收到异常,因为您无法再写入ByteArrayOutputStream
。
我认为在当前方法中解决此问题的任何尝试都已足够,因为在documentation中明确指出
通常,一个线程从PipedInputStream对象读取数据,而其他线程将数据写入相应的PipedOutputStream。 建议不要尝试使用单个线程中的两个对象,因为它可能使线程死锁。
因此,使用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();
}
时,一种解决方案虽然效率不高,但却是如此:
PipedInputStream
通常,PDF的大小不是很大,因此您可以将自己存储在内存中。如果要优化内存消耗,则应在单独的线程中执行PDF处理。我建议您查看this文章或搜索PipedOutputStream
与#include <iostream>
#include <string>
using namespace std;
int main(){
while(true){
int m = 0,n = 10;
char check;
while(true){
cout << "Enter please number m and which digit you want to select";
cin >> m >> n;
string m_new = to_string(m);
if(m_new.length() > n)
break;
else
cout << "n must be less than or equal to m";
}
cout << "The position" << n << "Of integer" << m << "is:" << m_new.substr(n,1);
cout << "Do you want to try again?(y/n)\n";
cin >> check;
while(check != 'y'&& check != 'n'){
cout <<"Please enter y or n\n";
cin >> check;
}
if(check == 'n'){
break;
}
}
return 0;
}
一起使用的一般示例。