web-dev-qa-db-ja.com

大きなxlsxファイルの処理

大きな(30k行以上)xlsxファイルのすべての行を自動調整する必要があります。

Apache poiを介した次のコードは小さなファイルで動作しますが、大きなファイルではOutOfMemoryErrorとともに出力されます。

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

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

workbook.write(outputStream);

更新:残念ながら、ヒープサイズを増やすことはオプションではありません-OutOfMemoryError-Xmx1024mおよび3万行は上限ではありません。

34
miah

イベントAPIを使用してみてください。詳細については、POIドキュメントの Event API(HSSFのみ) および XSSFおよびSAX(Event API) を参照してください。そのページからの引用:

HSSF:

イベントAPIは、ユーザーAPIよりも新しいです。これは、低レベルのAPI構造を少し学習したい中間開発者を対象としています。使用方法は比較的簡単ですが、Excelファイルの各部の基本的な理解(または学習意欲)が必要です。提供される利点は、XLSを比較的小さなメモリフットプリントで読み取ることができることです。

XSSF:

メモリフットプリントが問題になる場合は、XSSFの場合、基礎となるXMLデータを取得して自分で処理できます。これは、.xlsxファイルの低レベル構造を少しでも学習したいと考えているJava開発者を対象としています。比較的簡単に使用できますが、ファイル構造の基本的な理解が必要です。提供される利点は、比較的小さなメモリフットプリントでXLSXファイルを読み取ることができることです。

出力については、ブログ投稿 xlsxファイルのストリーミング で可能なアプローチの1つを説明しています。 (基本的に、XSSFを使用してコンテナXMLファイルを生成し、実際のコンテンツをプレーンテキストとしてxlsx Zipアーカイブの適切なxml部分にストリーミングします。)

33
markusk

ストリームの代わりにファイルを使用すると、メモリ使用量を劇的に改善できます。 (ストリーミングAPIを使用することをお勧めしますが、ストリーミングAPIには制限があります。 http://poi.Apache.org/spreadsheet/index.html を参照してください)

代わりに

Workbook workbook = WorkbookFactory.create(inputStream);

行う

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

これは次のとおりです: http://poi.Apache.org/spreadsheet/quick-guide.html#FileInputStream

Files vs InputStreams

「.xls HSSFWorkbookまたは.xlsx XSSFWorkbookのいずれかでワークブックを開くと、ワークブックはFileまたはInputStreamからロードできます。Fileオブジェクトを使用すると、メモリの消費が少なくなりますが、InputStreamはより多くのメモリを必要とします。ファイル全体をバッファリングします。」

10
rjdkolb

私は同じ問題をはるかに少ない行で、しかし大きな文字列で抱えていました。

データをロードし続ける必要がないため、XSSFの代わりにSXSSFを使用できることがわかりました。

これらには同様のインターフェースがあり、すでに多くのコードが記述されている場合に役立ちます。ただし、SXSSFを使用すると、ロードし続ける行の量を設定できます。

こちらがリンクです。 http://poi.Apache.org/spreadsheet/how-to.html#sxssf

3
DomLavoie

スタイルを自動調整または設定する場合、またはすべての行を大きな(30k行以上)xlsxファイルに書き込む場合は、SXSSFWorkbookを使用します。

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");
2
Santosh Gdr

HSSFファイル(.xls)にイベントAPIを使用しましたが、レコードの順序に関するドキュメントがひどく不足していることがわかりました。

1
ArturoTena

XSSFが1GBのヒープを割り当てる800,000のセルと3Mの文字で同じ問題が発生しました!

Pythonとopenpyxlおよびnumpyを使用してxlsxファイルを読み取り(Javaコード)から最初に変換する通常のテキストです。その後、Javaでテキストファイルをロードしました。大きなオーバーヘッドがあるように見えますが、実際には高速です。

pythonスクリプトは次のようになります

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()

それから私のJavaコードで、私は書きました

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() );
}

その後、foo.xlsxに似ていますが、テキスト形式のfoo.txtを取得します。

0
mahmood

SAXパーサーを使用してXML構造を処理しました。 XLSXファイルで機能します。

https://stackoverflow.com/a/44969009/4587961

0
Yan Khonski

XLSXにwritingを使用している場合、同じExcelファイルの異なるシートに書き込むことで改善が見られました。また、異なるExcelファイルに書き込むことで改善される場合があります。ただし、最初に別のシートに書き込んでみてください。

0
Alexander Mills

この最良の例は、次のスタックオーバーフロースレッドで説明されています。 Apache POI を介した大きなExcelファイル(xlsx)の読み取り中のエラー

そのトピックの主な回答のコードスニペットは、SAX xml解析に関するApache POIのラッピングと、すべてのシートを個々のセルで簡単にループする方法を示しています。

EndRow()apiは処理が終了した現在の行番号を提供するため、Apache POI APIの現在の実装ではコードが古くなっています。

このコードスニペットを使用すると、大きなXLSXファイルをセルごとに解析するのは簡単です。例えば。各シート用;行セルごと。行はイベントを終了しました。各行のcolumneNameからcellValueへのマップを作成するアプリロジックを簡単に作成できます。

0
99Sono