Apache POI com excel grande

6 respostas
marcoacsilva

Pessoal,

Estou precisando de uma mega ajuda. Estou desenvolvendo um programa em java para transferir os dados de um arquivo XLSX para dentro da nossa base de dados ORACLE.
Estou utilizando a API Apache POI para isto, porém, ao abrir o arquivo, o programa está estourando a memória.

O arquivo tem aproximadamento 41 colunas e ± 72 mil linhas.

Ele pesa em torna de 15,1MB.

Segue o código para vocês darem uma olhada.

package exportamdocs;

import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Iterator;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFRow;

public class Main {
    public static void main(String args[]) throws IOException, SQLException {
        
        XSSFWorkbook wbk = new XSSFWorkbook(new FileInputStream("C:\\Users\\739274\\Desktop\\teste.xlsx"));
        XSSFSheet sheets = wbk.getSheetAt(0);
        Iterator rows = sheets.rowIterator();
        int coluna = 0;   
        Conexao con = new Conexao();
        Connection conn = con.getConexao();
        PreparedStatement pst = conn.prepareStatement("insert into teste_mis_amdocs(DT_CRIACAO_ORDEM, DT_CANCEL_VENDA, ORDEM_COD, DT_VENDA, CLIENTE_CPF, CLIENTE_CNPJ, CLIENTE_TELEFONE, ENDERECO_CIDADE, ENDERECO_BAIRRO, ENDERECO_DISTRITO, ENDERECO_ZONA, ENDERECO_TIPO_LOGRADOURO, ENDERECO_LOGRADOURO, ENDERECO_CEP, ORDEM_TIPO, ORDEM_STATUS, DT_INSTAL_CONTRATO, ORDEM_COD_ACAO, ORDEM_MOTIVO_CANCELAMENTO, CLIENTE_COD_CONTRATO, CLIENTE_COD, CLIENTE_NOME, ENDERECO_ESTADO, ENDERECO_NUMERO, ENDERECO_COMPLEMENTO, ORDEM_STATUS_PROCESSO, DT_CONCLUSAO_TOA, ORDEM_COD_1) VALUES(?, ?, ?, ?, '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', ?, ?, '?', ?, ?, '?', '?', '?', '?', '?', ?, '?')");
        PreparedStatement pstt = conn.prepareStatement("truncate table teste_mis_amdocs");
        pstt.execute();
        while( rows.hasNext()){   
            XSSFRow Hrow = (XSSFRow) rows.next();   
            
            if(Hrow.getRowNum() != 0) {
                pst.setString(1,String.valueOf(Hrow.getCell(0)));
                pst.setString(2,String.valueOf(Hrow.getCell(1)));
                pst.setString(3,String.valueOf(Hrow.getCell(2)));
                pst.setString(4,String.valueOf(Hrow.getCell(3)));
                pst.setString(5,String.valueOf(Hrow.getCell(4)));
                pst.setString(6,String.valueOf(Hrow.getCell(5)));
                pst.setString(7,String.valueOf(Hrow.getCell(6)));
                pst.setString(8,String.valueOf(Hrow.getCell(7)));
                pst.setString(9,String.valueOf(Hrow.getCell(8)));
                pst.setString(10,String.valueOf(Hrow.getCell(9)));
                pst.setString(11,String.valueOf(Hrow.getCell(10)));
                pst.setString(12,String.valueOf(Hrow.getCell(11)));
                pst.setString(13,String.valueOf(Hrow.getCell(12)));
                pst.setString(14,String.valueOf(Hrow.getCell(13)));
                pst.setString(15,String.valueOf(Hrow.getCell(14)));
                pst.setString(16,String.valueOf(Hrow.getCell(15)));
                pst.setString(17,String.valueOf(Hrow.getCell(16)));
                pst.setString(18,String.valueOf(Hrow.getCell(17)));
                pst.setString(19,String.valueOf(Hrow.getCell(18)));
                pst.setString(20,String.valueOf(Hrow.getCell(19)));
                pst.setString(21,String.valueOf(Hrow.getCell(20)));
                pst.setString(22,String.valueOf(Hrow.getCell(21)));
                pst.setString(23,String.valueOf(Hrow.getCell(22)));
                pst.setString(24,String.valueOf(Hrow.getCell(23)));
                pst.setString(25,String.valueOf(Hrow.getCell(24)));
                pst.setString(26,String.valueOf(Hrow.getCell(25)));
                pst.setString(27,String.valueOf(Hrow.getCell(26)));
                pst.setString(28,String.valueOf(Hrow.getCell(27)));
                pst.execute();
                coluna++;
            }
        }
        pst.close();
        pstt.close();
        conn.close();
        con = null;
        System.out.println("Foram inseridos " + coluna + " registros no banco.");
    }
}

O erro acontece justamente quando tento passar o arquivo XLSX para o objeto.

XSSFWorkbook wbk = new XSSFWorkbook(new FileInputStream("C:\\Users\\739274\\Desktop\\teste.xlsx"));

Já tentei colocar o argumento de 1GB de memória para a VM, mas não adiantou.

O computador possúi 3GB de RAM. O máximo que consigo disponibilizar para a VM é -Xms1408m. Mais do que isso a VM não inicializa. E mesmo assim está estourando a memória.

O erro que apresenta é este:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:2271)
	at java.io.ByteArrayOutputStream.toByteArray(ByteArrayOutputStream.java:178)
	at org.apache.poi.openxml4j.util.ZipInputStreamZipEntrySource$FakeZipEntry.<init>(ZipInputStreamZipEntrySource.java:131)
	at org.apache.poi.openxml4j.util.ZipInputStreamZipEntrySource.<init>(ZipInputStreamZipEntrySource.java:55)
	at org.apache.poi.openxml4j.opc.ZipPackage.<init>(ZipPackage.java:83)
	at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:267)
	at org.apache.poi.util.PackageHelper.open(PackageHelper.java:39)
	at org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:204)
	at exportamdocs.Main.main(Main.java:16)

Obrigado desde já.

6 Respostas

A

Já usei POI e por simplicidade optei trocar por JExcel… Não sei te dizer se ela ajudaria a contornar seu problema de memória, mas de repente vale o risco…

A

duplicou a resposta porque deu erro ao enviar…

marcoacsilva

Eu cheguei a pesquisar o JExcel, mas ele só trabalho com arquivos XLS e eu preciso ler arquivos XLSX por conta da quantidade de linhas.

Arquivos XLS só aguentam até 65 mil linhas ±…A planilha menor que eu trabalho é essa de 72 mil linhas…

Sem contar uma outra que tem 203 mil…E por ai vai…

Estava pensando em transformar as planilhas em arquivos txt para ler a partir deles, mas não sei se seria uma boa…

A

Talvez seja mais simples salvar a planilha como CSV (própria opção do excel).

Com o loader do oracle, talvez nem precise criar um programa pra fazer a importação.

T

marcoacsilva,

Não sei se te ajuda, mas um arquivo XLSX nada mais é, a grosso modo, do que um arquivo ZIP. Tenta abrir ele no Winrar, por exemplo, e verá que tem um XML com os dados do arquivo. Minha sugestão seria: e se seu programa descompactar este XML e ler o XML direto ao invés de usar Apache POI?

Eu utilizei esta solução no sentido inverso, precisava gerar um arquivo xlsx com 600mil registros e com Apache POI sempre dava estouro de memória. Resolvi gerar um XML na estrutura do excel, e mover pra dentro do “ZIP” (do xlsx) e resolveu meu problema.

marcoacsilva

Obrigado a todos pela ajuda, mas não consegui abrir o arquivo excel.

Minhas solução foi transferir os dados para um arquivo txt separando as colunas pela tabulação e ler o arquivo pelo java. Ficou mais rápido, inclusive.

Valeu.

Criado 6 de março de 2013
Ultima resposta 9 de mar. de 2013
Respostas 6
Participantes 4