POIを使用してExcelを操作する際の注意点


まず、今私が知っているJava編集Excelファイルの2つのオープンソースツール:jakarta POIとJavaExcelAPI(JXLと略称)についてお話しします.この2つのツールは、この時間を試してみましたが、それぞれ優劣があるような気がします.POIはいくつかの細部に小さなBugがあり、画像の書き込みをサポートしていないので、他の面ではいいです.JXLは惨めで、画像の書き込みをサポートする以外に、私はしばらくPOIより良いところが見えません.私が出会った主な問題は公式のサポートがあまりよくないことです.多くの公式付きExcelファイルをJXLで開くと、公式が失われます(例えばnow()、today())、ネット上で他のエビのコメントを見てJXLの書き込み公式にも問題があると言いました.また、JXLがExcelファイルを操作する効率はPOIより少し低い.比較した後、私はPOIを選んで私のプロジェクトを開発しました.今私がしなければならないことは基本的に完成しました.私はこの間POIを使ったいくつかの心得をまとめました.私と同じ問題に遭遇した友达に役に立つことを望んでいます.POIの基本的な使い方については、自分でドキュメントを見に行きましょう.1、改ページを設定するbugPOIのHSSFSheetクラスはsetRowBreakメソッドを提供し、Sheetの改ページを設定することができる.Bug:改ページを設定するSheetが本来あり、そこに過度なページを挿入していない場合は、setRowBreakを呼び出すとPOIが空のポインタの異常を放出します.解決方法:Excelでこのsheetに改ページを挿入し、POIで開いてから削除すると、任意に改ページを挿入できます.sheetがPOIによって生成された場合、この問題はありません.setRowBreakのソースコードを追跡したところ、Sheetだった.Javaの下のPageBreakRecord rowBreaksという変数は、Sheetにもともと改ページがなかったら、このモジュールを開発した兄がこのオブジェクトnewインスタンスを忘れたので、まずExcelに改ページを手動で挿入してPOIがrowBreaksのためにインスタンスを作成することをトリガーするしかありません.2、コピーの仕方gmane.orgのPOIユーザーフォーラムは関連するすべての投稿をめくって、apiを探して、1つのコピー行の方法を見ていないで、仕方がなくて、自分で書くしかありません:
// :this.fWorkbook   HSSHWorkbook,      new
    public void copyRows
    (String pSourceSheetName, 
    String pTargetSheetName, 
    int pStartRow, int pEndRow,
    int pPosition)
    {
    HSSFRow sourceRow = null;
    HSSFRow targetRow = null;
    HSSFCell sourceCell = null;
    HSSFCell targetCell = null;
    HSSFSheet sourceSheet = null;
    HSSFSheet targetSheet = null;
    Region region = null;
    int cType;
    int i;
    short j;
    int targetRowFrom;
    int targetRowTo;
    
    if ((pStartRow == -1) || (pEndRow == -1))
    {
      return;
    }
    sourceSheet = this.fWorkbook.getSheet(pSourceSheetName);
    targetSheet = this.fWorkbook.getSheet(pTargetSheetName);
    //        
    for (i = 0; i < sourceSheet.getNumMergedRegions(); i++)
    {
    region = sourceSheet.getMergedRegionAt(i);
    if ((region.getRowFrom() >= pStartRow) && (region.getRowTo() <= pEndRow))
    {
    targetRowFrom = region.getRowFrom() - pStartRow + pPosition;
    targetRowTo = region.getRowTo() - pStartRow + pPosition;
    region.setRowFrom(targetRowFrom);
    region.setRowTo(targetRowTo);
    targetSheet.addMergedRegion(region);
    }
    } 
    //    
    for (i = pStartRow; i <= pEndRow; i++)
    {
    sourceRow = sourceSheet.getRow(i);
    if (sourceRow != null)
    {
    for (j = sourceRow.getFirstCellNum(); j < sourceRow.getLastCellNum(); j++)
    {
    targetSheet.setColumnWidth(j, sourceSheet.getColumnWidth(j));
    }
    break;
    }
    }
    //        
    for (;i <= pEndRow; i++)
    {
    sourceRow = sourceSheet.getRow(i);
    if (sourceRow == null)
    {
    continue;
    }
    targetRow = targetSheet.createRow(i - pStartRow + pPosition);
    targetRow.setHeight(sourceRow.getHeight());
    for (j = sourceRow.getFirstCellNum(); j < sourceRow.getLastCellNum(); j++)
    {
    sourceCell = sourceRow.getCell(j);
    if (sourceCell == null)
    {
    continue;
    }
    targetCell = targetRow.createCell(j);
    targetCell.setEncoding(sourceCell.getEncoding());
    targetCell.setCellStyle(sourceCell.getCellStyle());
    cType = sourceCell.getCellType();
    targetCell.setCellType(cType);
    switch (cType)
    {
    case HSSFCell.CELL_TYPE_BOOLEAN: 
    targetCell.setCellValue(sourceCell.getBooleanCellValue());
    break;
    case HSSFCell.CELL_TYPE_ERROR:
    targetCell.setCellErrorValue(sourceCell.getErrorCellValue());
    break;            
    case HSSFCell.CELL_TYPE_FORMULA:
    //parseFormula            
    targetCell.setCellFormula(parseFormula(sourceCell.getCellFormula()));
    break;
    case HSSFCell.CELL_TYPE_NUMERIC:
    targetCell.setCellValue(sourceCell.getNumericCellValue());
    break;
    case HSSFCell.CELL_TYPE_STRING:
    targetCell.setCellValue(sourceCell.getStringCellValue());
    break;
    }
    }
    }
    }

この関数には2つの問題が一時的に解決できません.a、同じワークブックでしか使用できません.ワークブックをまたぐとコピーできません.なぜか分かりません.b、コピー行でも行の高さをコピーしたので、これらのセルに書き込まれたデータの長さがセルの長さを超えると、自動的に行の高さを調整しません!3、式の問題POIはExcel式に対するサポートはかなり良いですが、もし式の中の関数がパラメータを持たないならば、例えばnow()あるいはtoday()で、getCellFormula()を通じて取り出した値はnow(ATTR(semiVolatile))とtoday(ATTR(semiVolatile))で、このような値がExcelに書き込まれるのは間違いです.これも私の上のcopyRowの関数が公式を書く前にparseFormulaを呼び出す理由で、parseFormulaという関数の機能は簡単で、ATTR(semiVolatile)を削除して、私はそのコードを貼り付けます:
private String parseFormula(String pPOIFormula)
    {
    final String cstReplaceString = "ATTR(semiVolatile)"; //$NON-NLS-1$
    StringBuffer result = null;
    int index;
    
    result = new StringBuffer();
    index = pPOIFormula.indexOf(cstReplaceString);
    if (index >= 0)
    {
    result.append(pPOIFormula.substring(0, index));
    result.append(pPOIFormula.substring(index + cstReplaceString.length()));
    }
    else
    {
    result.append(pPOIFormula);
    }
    
    return result.toString();
    }

なぜATTR(semiVolatile)が現れたのかについては、皆さんの探求精神が必要です!
4、Excelに画像を書き込む問題.
私はPOIフォーラムに行って関連する招待状を調べて、2つの結論を得ました:
1、書き込み画像がサポートされていない;
2、書き込み画像をサポートし、EscherGraphics 2 dというClassで実現する.そこで私はEscherGraphics 2 dというClassを調べて、このClassがN個のdrawImage方法を提供していることを発見して、望外の私がコードを書き始めたことを喜んで、結果は1日調整して、ずっと効果が見えなくて、黔ロバの技術が貧しい私は仕方なくdrawImageという関数の内部に追跡するしかなくて、N個の関数の呼び出しを経て最下層の関数で最終的な答えを発見しました:
 
public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
   int sx2, int sy2, Color bgColor, ImageObserver imageobserver)
   {
   if (logger.check( POILogger.WARN ))
   logger.log(POILogger.WARN,"drawImage() not supported");
   return true;
   }

だから、これから第三者開発パッケージを使って、できるだけソースコードをダウンロードすることを強くお勧めします.そうすれば、問題に遭遇したとき、その内部がどのように実現されているかを見て、私の轍を踏まなくてもいいことが多いです.POIが画像を書き込むことができない以上、私たちはJXLに目を向けるしかありません.私がJXLで画像を書き込む機能は実現しました.払った代価はnow()とtoday()という関数が失われ、魚と熊掌を兼ねることはできません.