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はコンベアのようなもので、いろいろなレコードを順番に目の前に送ってくれますが、あなたは、異なるレコードによって異なる操作をすればいいのです.
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が一致しない場合、改行を説明すると、この行のデータを処理し、配列を空にして次の行を読み直すことができます.これが私が採用している行ごとの読み取り&操作の例です.