2011-02-04 24 views
28

Devo eseguire automaticamente l'adattamento di tutte le righe in file xlsx di grandi dimensioni (30k + righe).Elaborazione di file xlsx di grandi dimensioni

Il seguente codice tramite Apache POI funziona su file di piccole dimensioni, ma esce con OutOfMemoryError su quelli grandi:

Workbook workbook = WorkbookFactory.create(inputStream); 
Sheet sheet = workbook.getSheetAt(0); 

for (Row row : sheet) { 
    row.setHeight((short) -1); 
} 

workbook.write(outputStream); 

Aggiornamento: Purtroppo, aumentando la dimensione heap non è un'opzione - OutOfMemoryError appare alla -Xmx1024m e 30k righe non è un limite superiore.

+0

Dove si esegue questo codice? App interna/server Web o autonomo? – JSS

+0

Lo sto eseguendo all'interno di Tomcat 6.0 – miah

+0

Che cosa è la memoria di default assegnata a Tomcat all'avvio? – JSS

risposta

31

Prova a utilizzare l'API dell'evento. Vedere Event API (HSSF only) e XSSF and SAX (Event API) nella documentazione POI per i dettagli. Un paio di citazioni da quella pagina:

HSSF:

The event API is newer than the User API. It is intended for intermediate developers who are willing to learn a little bit of the low level API structures. Its relatively simple to use, but requires a basic understanding of the parts of an Excel file (or willingness to learn). The advantage provided is that you can read an XLS with a relatively small memory footprint.

XSSF:

If memory footprint is an issue, then for XSSF, you can get at the underlying XML data, and process it yourself. This is intended for intermediate developers who are willing to learn a little bit of low level structure of .xlsx files, and who are happy processing XML in java. Its relatively simple to use, but requires a basic understanding of the file structure. The advantage provided is that you can read a XLSX file with a relatively small memory footprint.

Per l'uscita, un possibile approccio è descritto nel post del blog Streaming xlsx files. (Fondamentalmente, usa XSSF per generare un file XML contenitore, quindi invia il contenuto vero e proprio come testo normale nella parte xml appropriata dell'archivio zip xlsx.)

+1

Ciao anche io ho lo stesso problema di leggere file excel di grandi dimensioni. Eliminare i problemi di memoria. Ho visto http://poi.apache.org/spreadsheet/how-to.html#xssf_sax_api e non specifica come leggere i file excel. Per favore aiuto. – ashishjmeshram

+0

@Ashish: Si prega di inviare la vostra richiesta come una domanda separata su Stack Overflow con maggiori dettagli. In questo modo, anche altri utenti possono aiutarti. – markusk

+0

Per leggere grandi file Excel puoi dare un'occhiata a questa piccola e semplice libreria: https://github.com/davidpelfree/sjxlsx –

1

Ho usato API Event per un file HSSF (.xls), e Ho scoperto una terribile mancanza di documentazione sull'ordine dei record.

+0

So che questo è vecchio: ma hai trovato qualcosa sull'ordine degli eventi in HSSF e/o XSSF? – cripox

3

ho avuto lo stesso problema con molto meno di fila, ma stringhe di grandi dimensioni.

Poiché non devo caricare i miei dati, ho scoperto che posso usare SXSSF anziché XSSF.

Hanno interfacce simili, il che aiuta se hai già un sacco di codice scritto. Ma con SXSSF è possibile impostare la quantità di righe che si continuano a caricare.

Questo è il collegamento. http://poi.apache.org/spreadsheet/how-to.html#sxssf

10

Un notevole miglioramento nell'utilizzo della memoria può essere eseguito utilizzando un file anziché uno streaming. (E 'meglio utilizzare un'API di streaming, ma l'API Streaming di avere dei limiti, vedi http://poi.apache.org/spreadsheet/index.html)

Così, invece di

Workbook workbook = WorkbookFactory.create(inputStream); 

fare

Workbook workbook = WorkbookFactory.create(new File("yourfile.xlsx")); 

Questo è secondo: http://poi.apache.org/spreadsheet/quick-guide.html#FileInputStream

File vs InputStreams

"Quando si apre una cartella di lavoro, un HSSFWorkbook .xls o un XSSFWorkbook .xlsx, la cartella di lavoro può essere caricata da un file o da un InputStream.Utilizzo di un file oggetto consente il consumo di memoria inferiore, mentre un InputStream richiede più memoria in quanto ha per tamponare l'intero file."

+0

Questo mi dà un errore affermando: 'Caught: java.lang.LinkageError: violazione del vincolo del loader: quando si risolve il metodo dell'interfaccia" org.xml.sax.XMLReader.setEntityResolver (Lorg/xml/sax/EntityResolver;) V "il caricatore di classi (istanza di org/ codehaus/groovy/tools/RootLoader) della classe corrente, org/dom4j/io/SAXReader e il programma di caricamento classi (istanza di ) per la classe di definizione del metodo, org/xml/sax/XMLReader, sono diversi oggetti C lass per il tipo org/xml/sax/EntityResolver utilizzato nella firma 'Sto usando' poi-3.9' – kiltek

+1

@rjdkolb puoi vedere il mio post https://stackoverflow.com/questions/48772021/how -to-risolvere-the-java-heap-spazio-error-durante-carico-il-grande-xls-file-con-po – Mandrek

0

Se siete scrivendo a XLSX, ho trovato un miglioramento scrivendo a diversi fogli della stesso file di Excel.Potresti anche trovare un miglioramento scrivendo su file Excel diversi, ma prima prova a scrivere su diversi fogli

2

Se vuoi adattare o impostare stili o scrivere tutte le righe in grande (30k + righe) xlsx file, utilizzare SXSSFWorkbook.Here è il codice di esempio che ti aiuta ...

SXSSFWorkbook wb = new SXSSFWorkbook(); 
      SXSSFSheet sheet = (SXSSFSheet) wb.createSheet("writetoexcel"); 
      Font font = wb.createFont(); 
       font.setBoldweight((short) 700); 
       // Create Styles for sheet. 
       XSSFCellStyle Style = (XSSFCellStyle) wb.createCellStyle(); 
       Style.setFillForegroundColor(new XSSFColor(java.awt.Color.LIGHT_GRAY)); 
       Style.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND); 
       Style.setFont(font); 
       //iterating r number of rows 
      for (int r=0;r < 30000; r++) 
      { 
       Row row = sheet.createRow(r); 
       //iterating c number of columns 
       for (int c=0;c < 75; c++) 
       { 
        Cell cell = row.createCell(c); 
        cell.setCellValue("Hello"); 
        cell.setCellStyle(Style); 
       } 
    } 
      FileOutputStream fileOut = new FileOutputStream("E:" + File.separator + "NewTest.xlsx"); 
0

Il miglior esempio di questo è descritto in questo thread di stack overflow: Error While Reading Large Excel Files (xlsx) Via Apache POI

Il frammento di codice nella risposta principale di questo argomento illustra gli involucri Apache POI vicino SAX xml parsing, e come si può banalmente ciclo su tutta la fogli e poi su ogni singola cella.

Il codice è aggiornato con l'implementazione corrente dell'API API di Apache, poiché l'API di endRow() fornisce il numero di riga corrente che è terminato di essere elaborato.

Con questo frammento di codice dovrebbe essere banale per l'analisi di un grande file XLSX cella per cella. Per esempio. per ogni foglio; per ogni cella di riga; la riga ha terminato l'evento. È possibile creare in modo banale la logica dell'app dove, su ogni riga, si crea una mappa di nomeColonna su cellaValore.

0

Ho avuto lo stesso problema con 800.000 celle e 3 milioni di caratteri in cui XSSF alloca 1 GB di heap!

Ho usato Python con openpyxl e numpy per leggere il file xlsx (dal codice Java) e convertirlo prima in un testo normale. Quindi ho caricato il file di testo in java. Potrebbe sembrare che abbia un grande sovraccarico, ma è davvero veloce.

Lo script python sembra

import openpyxl as px 
import numpy as np 

# xlsx file is given through command line foo.xlsx 
fname = sys.argv[1] 
W = px.load_workbook(fname, read_only = True) 
p = W.get_sheet_by_name(name = 'Sheet1') 

a=[] 
# number of rows and columns 
m = p.max_row 
n = p.max_column 

for row in p.iter_rows(): 
    for k in row: 
     a.append(k.value) 

# convert list a to matrix (for example maxRows*maxColumns) 
aa= np.resize(a, [m, n]) 

# output file is also given in the command line foo.txt 
oname = sys.argv[2] 
print (oname) 
file = open(oname,"w") 
mm = m-1 
for i in range(mm): 
    for j in range(n): 
     file.write("%s " %aa[i,j] ) 
    file.write ("\n") 

# to prevent extra newline in the text file 
for j in range(n): 
    file.write("%s " %aa[m-1,j]) 

file.close() 

Poi nel mio codice Java, ho scritto

try { 
    // `pwd`\python_script foo.xlsx foo.txt 
    String pythonScript = System.getProperty("user.dir") + "\\exread.py "; 
    String cmdline = "python " + pythonScript + 
        workingDirectoryPath + "\\" + fullFileName + " " + 
        workingDirectoryPath + "\\" + shortFileName + ".txt"; 
    Process p = Runtime.getRuntime().exec(cmdline); 
    int exitCode = p.waitFor(); 
    if (exitCode != 0) { 
    throw new IOException("Python command exited with " + exitCode); 
    } 
} catch (IOException e) { 
    System.out.println(e.getMessage()); 
} catch (InterruptedException e) { 
    ReadInfo.append(e.getMessage()); 
} 

Dopo di che, si otterrà foo.txt che è simile a foo.xlsx, ma in formato di testo

Problemi correlati