2017-10-17 121 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的通用示例。

相關問題