POIを使用した大量のExcelテーブルデータの操作
xls形式で保存されているデータを解析する必要があるため、Javaの操作excelファイルのライブラリをネットで検索すると、ApacheのPOIが発見された.「Apache POIはApacheソフトウェア財団のオープンソース関数ライブラリであり、POIはJavaプログラムにMicrosoft Office形式ファイルの読み取りと書き込みの機能を提供する..NETの開発者はNPOI(POI for.NET)を利用することができるPOIにアクセスする機能.」--ウィキペディア
POIは様々なofficeドキュメントを操作することができますが、excelはもちろんその1つにすぎません.
ダウンロード先:
http://poi.apache.org/download.html
公式サイトのquick guideアドレス:
http://poi.apache.org/spreadsheet/quick-guide.html
最も簡単な方法はPOIのuser model、つまりquick guideで紹介されている方法で、これはみんなが見ると分かりますし、言うまでもありません.しかし、この方法には限界があります.user modelを使用してxlsファイルを読み込むときにHSSFWorkbookオブジェクトをインスタンス化し、読み込むexcelファイルをロードします.データが非常に大きい場合、xlsファイルが2、3 MBを超えると、JVMのout of memory異常が発生すると言われています.私が処理するxlsファイルが20 mb以上あるように、この方法は適用されません.JVMのメモリ上限を上げようとしましたが、結果は役に立ちませんでした.
近道がないので、私はまたインターネットで調べ直しました.このような大きなファイルに対処するには、一度に読むのは現実的ではありません.POIはevent user modelを提供して線形読み書き操作を行いました.このevent user modelは前のuser modelほど分かりにくいものではありません(名前から5文字増えるとわかります).公式サイトのコードは非常に難解で、その後、インターネットで多くの類似のコードを検索し、多くの場合、わけのわからないコードにいくつかの注釈を追加した.ここで私の理解について話します.
event modelは、POIがexcelを処理する際に採用するイベント処理メカニズムを説明し、SAXがXMLデータを処理する方法に似ている.1つのxlsファイルはバイトストリームの列であり,POIから見ればRecordストリームの列と考えられる.したがって、POIは、Recordに対してイベント処理関数を規定することができ、POIは、Recordを線形に読み出し、1つのRecordが読み出されるたびに、そのイベント処理関数を呼び出すことができる.ユーザーがしなければならないのは、カスタムイベント処理関数です.POIはコンベアのようなもので、いろいろなレコードを順番に目の前に送ってくれますが、あなたは、異なるレコードによって異なる操作をすればいいのです.
Listenerコード
公式サイトによると、event user modelは基本的なexcelファイルのフォーマットを理解する必要があるという.実はこれも簡単で、簡単なxlsファイルを作って、プログラムを走ってPOIがこれらの各種レコードを出力する順序を知っています.ここでSSTRecord strRecについてお話ししますが、これはListenerではプライベート変数であり、集合クラスのようなもので、表のすべての文字列にこの変数が存在し、indexで取り出すため、プライベート変数として設定する必要があります.
POIは、レコードを厳格に順番に読み取り、各sheetの各行の各列の内容を巡回します.残りの操作方法はユーザー自身が設定します.
currentRowプロパティを設定して、現在読み込まれている場所を判断し、この行のデータを配列に存在させることができます.getRowを使用して得られた現在の行とcurrentRowが一致しない場合、改行を説明すると、この行のデータを処理し、配列を空にして次の行を読み直すことができます.これが私が採用している行ごとの読み取り&操作の例です.
POIは様々なofficeドキュメントを操作することができますが、excelはもちろんその1つにすぎません.
ダウンロード先:
http://poi.apache.org/download.html
公式サイトのquick guideアドレス:
http://poi.apache.org/spreadsheet/quick-guide.html
最も簡単な方法はPOIのuser model、つまりquick guideで紹介されている方法で、これはみんなが見ると分かりますし、言うまでもありません.しかし、この方法には限界があります.user modelを使用してxlsファイルを読み込むときにHSSFWorkbookオブジェクトをインスタンス化し、読み込むexcelファイルをロードします.データが非常に大きい場合、xlsファイルが2、3 MBを超えると、JVMのout of memory異常が発生すると言われています.私が処理するxlsファイルが20 mb以上あるように、この方法は適用されません.JVMのメモリ上限を上げようとしましたが、結果は役に立ちませんでした.
近道がないので、私はまたインターネットで調べ直しました.このような大きなファイルに対処するには、一度に読むのは現実的ではありません.POIはevent user modelを提供して線形読み書き操作を行いました.このevent user modelは前のuser modelほど分かりにくいものではありません(名前から5文字増えるとわかります).公式サイトのコードは非常に難解で、その後、インターネットで多くの類似のコードを検索し、多くの場合、わけのわからないコードにいくつかの注釈を追加した.ここで私の理解について話します.
event modelは、POIがexcelを処理する際に採用するイベント処理メカニズムを説明し、SAXがXMLデータを処理する方法に似ている.1つのxlsファイルはバイトストリームの列であり,POIから見ればRecordストリームの列と考えられる.したがって、POIは、Recordに対してイベント処理関数を規定することができ、POIは、Recordを線形に読み出し、1つのRecordが読み出されるたびに、そのイベント処理関数を呼び出すことができる.ユーザーがしなければならないのは、カスタムイベント処理関数です.POIはコンベアのようなもので、いろいろなレコードを順番に目の前に送ってくれますが、あなたは、異なるレコードによって異なる操作をすればいいのです.
public class tryEventModel {
private static final String TEST_FILE = "files/workbook.xls";
public static void main(String args[]) {
File file = new File(TEST_FILE);
FileInputStream fis;
try {
fis = new FileInputStream(file);
POIFSFileSystem pfs;
pfs = new POIFSFileSystem(fis);
InputStream is;
is = pfs.createDocumentInputStream("Workbook");
HSSFRequest request = new HSSFRequest();
// Record , , addListener , Record
request.addListenerForAllRecords(new MyListener());
HSSFEventFactory factory = new HSSFEventFactory();
factory.processEvents(request, is);
fis.close();
// TODO Auto-generated catch block
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Listenerコード
public class MyListener implements HSSFListener {
//
private SSTRecord strRec;
public void processRecord(Record record) {
switch (record.getSid()){
case BOFRecord.sid:
BOFRecord br = (BOFRecord)record;
switch (br.getType()) {
case BOFRecord.TYPE_WORKBOOK: // Workbook
System.out.println(" workbook");
break;
case BOFRecord.TYPE_WORKSHEET:// Worksheet, Event API Excel , sheet 。
System.out.println(" worksheet");
break;
}
break;
case BoundSheetRecord.sid: // sheet, sheet , sheet , List
BoundSheetRecord bsr = (BoundSheetRecord) record;
System.out.println("sheetName:"+bsr.getSheetname());
break;
case SSTRecord.sid: //
strRec = (SSTRecord)record;
System.out.println(" ");
break;
case RowRecord.sid: // ,
RowRecord rr = (RowRecord) record;
System.out.println(" :"+rr.getRowNumber()+"。 :"+rr.getFirstCol()+", :"+rr.getLastCol());
break;
case NumberRecord.sid: // cell, , , , , !!!!!!!
NumberRecord nr = (NumberRecord)record;
if(HSSFDateUtil.isInternalDateFormat(nr.getXFIndex())){
System.out.println(" :"+(new SimpleDateFormat("yyyy-MM-dd")).format(HSSFDateUtil.getJavaDate(nr.getValue()))
+", :"+nr.getRow()+ ", :"+nr.getColumn()+"。("+nr.getXFIndex()+")");
}else{
System.out.println(" :"+nr.getValue()+", :"+nr.getRow()+ ", :"+nr.getColumn()+"。("+nr.getXFIndex()+")");
}
break;
case LabelSSTRecord.sid: // , , index
LabelSSTRecord lsr = (LabelSSTRecord)record;
System.out.println(" :"+strRec.getString(lsr.getSSTIndex())+", :"+lsr.getRow()+", :"+lsr.getColumn());
break;
case BoolErrRecord.sid: //boolean or error
BoolErrRecord ber = (BoolErrRecord)record;
if(ber.isBoolean()){
System.out.println("Boolean:"+ber.getBooleanValue()+", :"+ber.getRow()+", :"+ber.getColumn());
}
if(ber.isError()){
System.out.println("Error:"+ber.getErrorValue()+", :"+ber.getRow()+", :"+ber.getColumn());
}
break;
case BlankRecord.sid:
BlankRecord br1 = (BlankRecord)record;
System.out.println(" 。 :"+br1.getRow()+", :"+br1.getColumn());
break;
case FormulaRecord.sid: //
FormulaRecord fr = (FormulaRecord)record;
break;
}
}
}
公式サイトによると、event user modelは基本的なexcelファイルのフォーマットを理解する必要があるという.実はこれも簡単で、簡単なxlsファイルを作って、プログラムを走ってPOIがこれらの各種レコードを出力する順序を知っています.ここでSSTRecord strRecについてお話ししますが、これはListenerではプライベート変数であり、集合クラスのようなもので、表のすべての文字列にこの変数が存在し、indexで取り出すため、プライベート変数として設定する必要があります.
POIは、レコードを厳格に順番に読み取り、各sheetの各行の各列の内容を巡回します.残りの操作方法はユーザー自身が設定します.
currentRowプロパティを設定して、現在読み込まれている場所を判断し、この行のデータを配列に存在させることができます.getRowを使用して得られた現在の行とcurrentRowが一致しない場合、改行を説明すると、この行のデータを処理し、配列を空にして次の行を読み直すことができます.これが私が採用している行ごとの読み取り&操作の例です.