Ошибка: Исключение конца файла при объединении двух PDF с помощью Apache PdfBox

Вопрос или проблема

Я пытаюсь объединить два файла .pdf – один приходит ко мне в виде массива байтов, второй я храню в ресурсе – затем мне нужно вернуть объединенные PDF в виде массива байтов. Я пытаюсь сделать это, используя временные файлы – я предпочитаю избегать создания и удаления папок локально – и используя Apache PdfBox. При выполнении pdfMergerUtility.mergeDocuments() я получил исключение End-of-File.

Мой код выглядит следующим образом:

 public byte[] mergedPdfs(byte[] byteArray) throws IOException {

       //Сначала я преобразую byteArray в .pdf и пытаюсь сохранить его как временный файл
        File pdfOneTemp = File.createTempFile("pdfOne", ".pdf");
        FileUtils.writeByteArrayToFile(pdfOneTemp, byteArray);
        InputStream pdfOne = new FileInputStream(pdfOneTemp);

        //Извлекаем второй .pdf из папки ресурсов (/pdf/pdfTwo.pdf)
        InputStream pdfTwo =
                Thread.currentThread()
                        .getContextClassLoader()
                        .getResourceAsStream("/pdf/pdfTwo.pdf");

        //ByteArrayOutputStream для потока назначения для PDFMergerUtility
        ByteArrayOutputStream mergedPdfs = new ByteArrayOutputStream();

        //PDFMergerUtility для объединения двух .pdf файлов
        PDFMergerUtility pdfMergerUtility = new PDFMergerUtility();
        pdfMergerUtility.setDestinationStream(mergedPdfs);
        pdfMergerUtility.addSource(pdfOne);
        pdfMergerUtility.addSource(pdfTwo);
        pdfMergerUtility.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());

        pdfOne.close();
        pdfTwo.close();
        
        return mergedPdfs.toByteArray();
    }

И трассировка стека:

SEVERE [org.primefaces.application.exceptionhandler.PrimeExceptionHandler] (default task-2) Error: End-of-File, expected line at offset 0: java.io.IOException: Error: End-of-File, expected line at offset 0
    at org.apache.pdfbox.pdfparser.BaseParser.readLine(BaseParser.java:1147)
    at org.apache.pdfbox.pdfparser.COSParser.parseHeader(COSParser.java:2651)
    at org.apache.pdfbox.pdfparser.COSParser.parsePDFHeader(COSParser.java:2634)
    at org.apache.pdfbox.pdfparser.PDFParser.parse(PDFParser.java:217)
    at org.apache.pdfbox.pdmodel.PDDocument.load(PDDocument.java:1237)
    at org.apache.pdfbox.pdmodel.PDDocument.load(PDDocument.java:1155)
    at org.apache.pdfbox.multipdf.PDFMergerUtility.legacyMergeDocuments(PDFMergerUtility.java:459)
    at org.apache.pdfbox.multipdf.PDFMergerUtility.mergeDocuments(PDFMergerUtility.java:349)
    at com.ista.dws.managedBean.searchContract.util.DoSomething.testFiles(DoSomething.java:125)
    at com.ista.dws.managedBean.searchContract.SearchContractActionBase.searchContracts(SearchContractActionBase.java:192)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at javax.el.ELUtil.invokeMethod(ELUtil.java:245)
    at javax.el.BeanELResolver.invoke(BeanELResolver.java:338)
    at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:198)
    at com.sun.el.parser.AstValue.invoke(AstValue.java:261)
    at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:280)
    at org.jboss.weld.module.web.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
    at org.jboss.weld.module.web.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
    at org.jboss.weld.module.web.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
    at org.jboss.weld.module.web.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
    at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:65)
    at com.sun.faces.application.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:66)
    at com.sun.faces.application.ActionListenerImpl.getNavigationOutcome(ActionListenerImpl.java:82)
    at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:71)
    at javax.faces.component.UICommand.broadcast(UICommand.java:222)
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:847)
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1395)
    at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:58)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:76)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:177)
    at javax.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:707)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:451)
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
    at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:81)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at io.opentracing.contrib.jaxrs2.server.SpanFinishingFilter.doFilter(SpanFinishingFilter.java:52)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at com.ista.shared.gui.jsf.utils.filter.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:21)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at io.undertow.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.server.handlers.DisableCacheHandler.handleRequest(DisableCacheHandler.java:33)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.security.handlers.AuthenticationConstraintHandler.handleRequest(AuthenticationConstraintHandler.java:53)
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.servlet.handlers.security.ServletSecurityConstraintHandler.handleRequest(ServletSecurityConstraintHandler.java:59)
    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
    at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
    at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
    at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
    at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
    at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1504)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1504)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1504)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1504)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
    at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
    at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1982)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
    at java.lang.Thread.run(Thread.java:750)

Я пытался сделать все, чтобы это сработало, но, к сожалению, не смог. Что я делаю не так?

Ответ или решение

Ошибка "End-of-File Exception" при слиянии PDF-документов с помощью Apache PdfBox может возникнуть по нескольким причинам. Давайте рассмотрим вашу реализацию и предложим возможные решения.

1. Анализ проблемы

Согласно вашему коду, вы пытаетесь объединить два PDF-файла: один из них представлен в виде массива байтов, а второй загружается из ресурсов вашего приложения. Ошибка "End-of-File, expected line at offset 0" указывает на то, что один из ваших входных PDF-файлов оказывается пустым или поврежденным.

Давайте разберемся в вашем коде:

public byte[] mergedPdfs(byte[] byteArray) throws IOException {
    // Создание временного файла для первого PDF
    File pdfOneTemp = File.createTempFile("pdfOne", ".pdf");
    FileUtils.writeByteArrayToFile(pdfOneTemp, byteArray);
    InputStream pdfOne = new FileInputStream(pdfOneTemp);

    // Получение второго PDF из ресурсов
    InputStream pdfTwo =
            Thread.currentThread()
                    .getContextClassLoader()
                    .getResourceAsStream("/pdf/pdfTwo.pdf");

    // Выводной поток для объединенных PDF
    ByteArrayOutputStream mergedPdfs = new ByteArrayOutputStream();

    // Объединение документов
    PDFMergerUtility pdfMergerUtility = new PDFMergerUtility();
    pdfMergerUtility.setDestinationStream(mergedPdfs);
    pdfMergerUtility.addSource(pdfOne);
    pdfMergerUtility.addSource(pdfTwo);
    pdfMergerUtility.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());

    // Закрытие потоков
    pdfOne.close();
    pdfTwo.close();

    return mergedPdfs.toByteArray();
}

2. Возможные причины ошибки

  1. Пустой байтовый массив: Убедитесь, что byteArray не является пустым. Вы можете добавить проверку:

    if (byteArray == null || byteArray.length == 0) {
       throw new IllegalArgumentException("Input byte array is null or empty");
    }
  2. PDF файл в ресурсе: Проверьте, действительно ли файл /pdf/pdfTwo.pdf существует и корректно загружается. Вы можете добавить проверку на null:

    if (pdfTwo == null) {
       throw new IOException("Resource not found: /pdf/pdfTwo.pdf");
    }
  3. Проблемы с временным файлом: Убедитесь, что временный файл создается и записывается без ошибок. Вы уже используете FileUtils.writeByteArrayToFile, но стоит убедиться, что запись действительно успешна.

3. Рекомендации по улучшению

  • Закрытие потоков: Рекомендуется использовать конструкцию try-with-resources для автоматического закрытия потоков:

    try (InputStream pdfOne = new FileInputStream(pdfOneTemp);
         InputStream pdfTwo = Thread.currentThread().getContextClassLoader().getResourceAsStream("/pdf/pdfTwo.pdf");
         ByteArrayOutputStream mergedPdfs = new ByteArrayOutputStream()) {
    
         // Объединение
    }
  • Логирование ошибок: Используйте логирование, чтобы отслеживать ошибки и исключения. Это поможет вам быстрее находить проблемные места в коде.

4. Заключение

Проверив вышеуказанные моменты, вы сможете устранить проблему "End-of-File Exception" при объединении ваших PDF-документов. Помните, что важно проверять как входные данные, так и состояние файлов, с которыми вы работаете. Надеемся, данная информация окажется полезной и поможет вам успешно завершить вашу задачу по объединению PDF-файлов. Якщо у вас є додаткові питання або потрібно більше інформації, не соромтеся запитувати.

Оцените материал
Добавить комментарий

Капча загружается...