2017-10-17 4 views
0

AWS S3 버킷에는 pdf 파일이 1 개 있습니다. 이 pdf 파일의 내용은 iText Java 라이브러리를 사용하여 편집해야합니다. 수정 된 파일은 S3 버킷에 다시 저장해야합니다. 현재 AWS 람다 함수를 사용하고 있습니다. 빈 pdf 파일은 AWS CloudWatch는 오류 메시지와 함께 대상 S3 버킷에 만들어지고 : "파이프 폐쇄"iText를 사용하여 AWS S3 버킷의 PDF 파일 편집

람다 자바 코드 :

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 객체에서 읽도록 적혀있다 충분 현재의 접근 방식에서이 문제를 해결하기 위해 생각하지 않는다 다른 thread가 대응하는 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을 사용하는 일반적인 예를 검색하는 것이 좋습니다.