Ler e Escrever arquivos Office 2003 e 2007 com Apache POI

5 respostas
S

Olá povo!

Tenho que construir uma aplicação em Java SE para ler e escrever em documentos do MS Office no padão OOXML (docx, xlsx, pptx,…).

Vi pela web que uma boa forma de se fazer isto é com a API Apache POI.

Dei uma olhada em alguns tutoriais pela web, mas a maioria se destina a ensinar a leitura e escrita do formato antigo do Office (doc, xls, ppt,…).

Alguém já trabalhou com esta ferramenta anteriormente? ou alguém tem um bom artigo (mesmo que em ingles) sobre o assunto?

Dei uma olhada no Javadoc da API para ao menos ver como se realiza a leitura de um arquivo. Mas achei um pouco complexa a forma de como ele trabalha o XML do conteiner zip do OOXML principalmente pelo fato de que eu tenho que manter o template padrão dos arquivos que já existem aqui e vim até aqui pedir auxilio.

bom, aguardo vocês para a ajuda! té mais!

5 Respostas

S

bom tive uns progressos.

tentei converter o arquivo que eu tinha pro formato doc pra ser mais facil de trabalhar (na verdade é pq tem mais exemplos por ai).

então acabei achando um código aqui pelo guj mesmo que trabalha com o Range e um mapa de strings pra localização e substituição do conteudo o arquivo:

vamos ao códEgo:

public static void replaceWord(InputStream fistream, Map<String, String> mapReplacement) {  
        try{  
            HWPFDocument word = new HWPFDocument(new POIFSFileSystem(fistream));  
  
            Range range = word.getRange();  
  
            for(String keySet : mapReplacement.keySet())  
                range.replaceText(keySet, mapReplacement.get(keySet));  
  
            OutputStream output = new FileOutputStream("DocTeste.doc");  
  
            word.write(output);  
        }catch(Exception e){  
            e.printStackTrace();  
        }  
    }

esse provavelmente é o mais efetivo dos códigos pra se trabalhar com um modelo doc.

crie campos no arquivo (como se fossem tags) que possam ser alteradas com um replace (por exempo "#remetente#"). e jogue isso num map e ele devolve um arquivo .doc modificado.
public static void main(String[] args) {
		HashMap<String, String> mapa = new HashMap<String, String>();
		mapa.put("#remetente#", "LOLOLOL");
		try {
			replaceWord(new FileInputStream(new File("MODELO.doc")), mapa);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

o problema é que meu modelo tem um header e um footer que contem imagens. o texto ele conseguiu jogar normalmente, mas as imagens não aparecem mais.

depois tentei algo parecido com um código pra trabalhar com XWPFDocument e XWPFWordExtractor

public static void reclace() throws IOException {  
        InputStream arquivoCarregado = new FileInputStream(new File("MODELmine.docx"));         
        XWPFDocument word = new XWPFDocument(arquivoCarregado); 
        XWPFWordExtractor extractor = new XWPFWordExtractor(word);
        String conteudo = extractor.getText();  
        conteudo = conteudo.replace("#nate_oper#", "Simpsons");
        
        FileOutputStream output = new FileOutputStream("testeteste.docx");  
        word.write(output);  
        output.flush();  
        output.close();  
    }

provavelmente este também funciona da mesma forma. eu consigo ver a saída do texto no console, mas não sei como escrever esses dados alterados corretamente no docx do meu modelo.

alguém sabe alguma coisa a respeito (sobre um ou ambos os casos)?

S

bom, consegui resolver.

public void _replaceWord(InputStream localArquivo, Map<String, String> mapa, String nomeArquivoSaida) throws Exception{  
        HWPFDocument word = new HWPFDocument(new POIFSFileSystem(localArquivo));  
        Range range = word.getRange();  
        for(String keySet : mapa.keySet())  
            range.replaceText(keySet, mapa.get(keySet));
        OutputStream output = new FileOutputStream(nomeArquivoSaida+".doc");  
        word.write(output);
        output.close();
    }

o grande lance estava na orientação da imagem.
o único modo que consegui foi deixar a imagem no template foi com o “Alinhada ao Texto”. Qualquer outro modo deu problema.

Então pra manter um padrão visual legal, coloquei as imagens dentro de uma tabela. ai funcionou de boa. mesmo no footer! ^^

S

Olá novamente.

Estou usando a versão 3.8 beta 4 do Apache POI para manipular um arquivo modelo que servirá como saída de relatório de alguns dados.

Neste caso o arquivo Office é do formato “doc” e estou usando o HWPFDocument para realizar a tarefa.

No modelo, eu tenho a seguinte estrutura:

Cabeçalho: Que contém uma imagem (a logomarca da empresa), o número de páginas, o cabeçalho propriamente dito e um texto que deverá ser impresso em todas as páginas geradas pelo relatório.

“Corpo”: aonde contém uma tabela com duas colunas e que são preenchidas dinamicamente.

Rodapé: Que é semelhante ao cabeçalho, mas que contém informações a serem preenchidas dinamicamente. E elos para o e-mail e site.

Usando isto:

HWPFDocument word = new HWPFDocument(new POIFSFileSystem(filePath));
     
        Range range = word.getRange();  //to replace the content in the cols of the tables in the "body".
        range.replaceText("#n_v_left#", map.get("#_n_v_left#"));
        range.replaceText("#n_v_right#", map.get("#n_v_right#"));

        HeaderStories hs = new HeaderStories(word);

        Range hsRange = hs.getRange();//to replace the content in header and footnote
        hsRange.replaceText("#day#", map.get("#day#"));
        hsRange.replaceText("#mon#", map.get("#mon#"));
        hsRange.replaceText("#yea#", map.get("#yea#"));
        hsRange.replaceText("#n_1#", map.get("#n_1#"));
        hsRange.replaceText("#n_2#", map.get("#n_2#"));
        hsRange.replaceText("#serial#", map.get("#serial#"));
        
        OutputStream output = new FileOutputStream(outputFileName+".doc");  
        output.flush();
        word.write(output);
        output.close();

Tudo ocorria bem. A API substitui as marcações corretamente, mas ela passou a apagar os links do rodapé e a colocar automaticamente um objeto de imagem no rodapé.

como na imagem: http://i32.photobucket.com/albums/d23/samirrolemberg/image.png
(a imagem é do modelo original que contém dados sigilosos, por isso os rabiscos).

Retirei as imagens e executei novamente a aplicação, mas ocorreu o mesmo problema.

Depois tentei voltar para uma versão estável da API (a 3.7) (utilizando os mesmos metodos de substituição) mas, quando eu tento salvar um arquivo, o arquivo criado é gerado como um arquivo inválido e corrompido.

E agora não sei mais o que fazer! alguém já teve esse “problema”?

P

Olá samirrolemberg.

Quando li o seu post fiquei muito animado pois é exatamente o meu problema.
Cabeçalho Rodapé imagem e tudo mais que possa existir dentro de um documento WORD.

Mas enfim a uns 10 dias venho dando marretadas com a POI, show de biblioteca, mas o problema é o WORD, que tem uma formatação própria,resumindo a história vou postar o que eu fiz para solucionar o meu problema.

Peguei o meu documento do WORD e salvei eu ODT (OpenOffice), no meu caso não alterou nada com relação a apresentação da página, então utilizei 2 bibliotécas jodreports-2.4.0.jar e jodreports-cli-2.4.0-jar-with-dependencies.jar, e por incrível que pareça ficou tudo certo, cabeçalho no lugar, imagem no rodapé tabelas, grades e tudo mais, vale apenas conferir o exemplo em http://pedrocavalero.blogspot.com/2011/05/criando-documento-partir-de-templates.html

Vale lembrar que o meu documento do word é de 300k e em openOffice passou para 44k, vou economizar um grande espaço em disco.

Espero ter ajudado.

S

eu entrei na lista de discussão da API (na pagina em ingles)

há esse bug chato mesmo na poi 3.8 beta.

O mais estranho é que mesmo trocando a api pra uma versão mais estavel tb não funionava.

e trabalhar com odt não é opção pra mim, mas valeu pela dica.

Criado 31 de agosto de 2011
Ultima resposta 2 de out. de 2011
Respostas 5
Participantes 2