Apache POI com excel grande

6 respostas
M

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…

M

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.

M

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