2017-02-16 3 views
0

Я слияние нескольких файлов, изначально имевших 19 МБ.pdfbox записи сжатых потоков объектов

Но результат в общей сложности составляет 56 мб. Как я могу сделать этот окончательный подход стоимостью 19 мб. [EDIT]

public void concatena(InputStream anterior, InputStream novo, OutputStream saida, List<String> marcadores) 
    throws IOException { 
    PDFMergerUtility pdfMerger = new PDFMergerUtility(); 
    pdfMerger.setDestinationStream(saida); 
    PDDocument dest; 
    PDDocument src; 
    MemoryUsageSetting setupMainMemoryOnly = MemoryUsageSetting.setupMainMemoryOnly(); 
    if (anterior != null) {      
     dest = PDDocument.load(anterior, setupMainMemoryOnly); 
     src = PDDocument.load(novo, setupMainMemoryOnly); 
    } else { 
     dest = PDDocument.load(novo, setupMainMemoryOnly); 
     src = new PDDocument(); 
    }  
    int totalPages = dest.getNumberOfPages(); 
    pdfMerger.appendDocument(dest, src); 
    criaMarcador(dest, totalPages, marcadores); 
    saida = pdfMerger.getDestinationStream(); 
    dest.save(saida); 
    dest.close(); 
    src.close(); 
} 

К сожалению, я до сих пор не знаю, как использовать StackOverflow очень хорошо. Я выкладываю остальную часть кода, но я получаю сообщение об ошибке

[Edit 2 - добавить метод criaMarcador]

private void criaMarcador(PDDocument src, int numPaginas, List<String> marcadores) { 
    if (marcadores != null && !marcadores.isEmpty()) { 
     PDDocumentOutline documentOutline = src.getDocumentCatalog().getDocumentOutline();   
     if (documentOutline == null) { 
      documentOutline = new PDDocumentOutline(); 
     } 
     PDPage page; 
     if (src.getNumberOfPages() == numPaginas) { 
      page = src.getPage(0); 
     } else { 
      page = src.getPage(numPaginas); 
     } 
     PDOutlineItem bookmark = null; 
     PDOutlineItem pai = null; 
     String etiquetaAnterior = null; 
     for (String etiqueta : marcadores) {     
      bookmark = bookmark(pai != null ? pai : documentOutline, etiqueta); 
      if (bookmark == null) { 
       if (etiquetaAnterior != null && !etiquetaAnterior.equals(etiqueta) && pai == null) { 
        pai = bookmark(documentOutline, etiquetaAnterior); 
       } 
       bookmark = new PDOutlineItem(); 
       bookmark.setTitle(etiqueta); 
       if (marcadores.indexOf(etiqueta) == marcadores.size() - 1) { 
        bookmark.setDestination(page); 
       } 
       if (pai != null) { 
        pai.addLast(bookmark); 
        pai.openNode(); 
       } else { 
        documentOutline.addLast(bookmark); 
       } 
      } else { 
       pai = bookmark; 
      } 
      etiquetaAnterior = etiqueta; 
     } 
     src.getDocumentCatalog().setDocumentOutline(documentOutline);   
    }  
} 

private PDOutlineItem bookmark(PDOutlineNode outline, String etiqueta) {    
    PDOutlineItem current = outline.getFirstChild(); 
    while (current != null) { 
     if (current.getTitle().equals(etiqueta)) { 
      return current; 
     } 
     bookmark(current, etiqueta); 
     current = current.getNextSibling(); 
    } 
    return current; 
} 

[Редактировать 3] Вот код, который используется для тестирования

public class PDFMergeTeste { 


public static void main(String[] args) throws IOException { 
    if (args.length == 1) { 
     PDFMergeTeste teste = new PDFMergeTeste(); 
     teste.executa(args[0]); 
    } else { 
     System.err.println("Argumento tem que ser diretorio contendo arquivos .pdf com nomeclatura no padrão Autos"); 
    } 
} 

private void executa(String diretorioArquivos) throws IOException { 
    File[] listFiles = new File(diretorioArquivos).listFiles((pathname) -> 
      pathname.getName().endsWith(".pdf") || pathname.getName().endsWith(".PDF")); 
    List<File> lista = Arrays.asList(listFiles); 
    lista.sort(Comparator.comparing(File::lastModified)); 
    PDFMerge merge = new PDFMerge(); 
    InputStream anterior = null; 
    ByteArrayOutputStream saida = new ByteArrayOutputStream(); 
    for (File file : lista) { 
     List<String> marcadores = marcadores(file.getName());   
     InputStream novo = new FileInputStream(file);   
     merge.concatena(anterior, novo, saida, marcadores);      
     anterior = new ByteArrayInputStream(saida.toByteArray()); 
    } 
    try (OutputStream pdf = new FileOutputStream(pathDestFile)) { 
     saida.writeTo(pdf); 
    } 


} 
private List<String> marcadores(String name) { 
    String semExtensao = name.substring(0, name.indexOf(".pdf")); 
    return Arrays.asList(semExtensao.split("_"));  
} 

}

+0

Пожалуйста, поделитесь своими файлами. И расскажи свою версию. –

+0

@TilmanHausherr https://www.dropbox.com/sh/elbjegfykxux6wf/AAC8SMU6-7_sAPS7yqgZkDn0a?dl=0 –

+0

@ArthurMenezes Эти файлы являются образцами файлов, которые вы должны объединить? – mkl

ответ

1

ошибка в методе executa:

InputStream anterior = null; 
ByteArrayOutputStream saida = new ByteArrayOutputStream(); 
for (File file : lista) { 
    List<String> marcadores = marcadores(file.getName());   
    InputStream novo = new FileInputStream(file);   
    merge.concatena(anterior, novo, saida, marcadores);      
    anterior = new ByteArrayInputStream(saida.toByteArray()); 
} 

Ваш ByteArrayOutputStream saida повторно используется в каждом цикле, но он не очищается между ними. Таким образом, она содержит

  • после обработки файла 1:
    • файл 1
  • после обработки файла 2:
    • файла 1
    • конкатенация файл 1 и файл 2
  • после обработки файла 3: файл 1
    • файл 1
    • конкатенация файл 1 и файл 2
    • конкатенации файла 1 и файл 2, и файл 3
  • после обработки файла 4:
    • файл 1
    • конкатенация файл 1 и файл 2
    • конкатенация файл 1 и файл 2 и файл 3
    • конкатенацию файл 1 и файл 2 и файл 3 и файл 4

(на самом деле это работает только потому, что PDFBox старается быть хорошим и исправления сломанные входные файлы под капотом, поскольку эти конкатенации файлов строго говоря нарушены, и PDFBox не должен разбираться в них.)

Вы можете исправить это, очищая saida в начале каждой итерации:

InputStream anterior = null; 
ByteArrayOutputStream saida = new ByteArrayOutputStream(); 
for (File file : lista) { 
    saida.reset(); 
    List<String> marcadores = marcadores(file.getName());   
    InputStream novo = new FileInputStream(file);   
    merge.concatena(anterior, novo, saida, marcadores);      
    anterior = new ByteArrayInputStream(saida.toByteArray()); 
} 

С оригинального методом размером результата для входов почти 26 МБ, с фиксированным способом это около 5 MB , и этот последний размер приблизительно представляет собой сумму размеров входных файлов.

+0

Это сработало! Спасибо за помощь. –

Смежные вопросы