jinfeng_wang

          G-G-S,D-D-U!

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            400 Posts :: 0 Stories :: 296 Comments :: 0 Trackbacks
          http://dev.w3pub.com/content/2007-5-1/2437.html


          上好的人肉包子新鮮出爐啦,各位妖魔鬼怪趕緊來嘗嘗鮮……

          首先說說現在我所知道的java編輯Excel文件的兩大開源工具:jakarta poi和JavaExcelAPI(簡稱JXL),這兩套工具我都試用了一這段時間,感覺各有優(yōu)劣吧。poi在某些細節(jié)有些小Bug并且不支持寫入圖片,其他方面都挺不錯的;JXL就慘了,除了支持寫入圖片外,我暫時看不到它比POI好的地方,我碰到的主要的問題就是對公式支持不是很好,很多帶有公式的Excel文件用JXL打開后,公式就丟失了(比如now(),today()),在網上看到其他大蝦評論說JXL寫入公式也有問題,另外,JXL操作Excel文件的效率比POI低一點。經過比較后,我選擇了poi開發(fā)我的項目。

          現在我要做的東西基本完成啦,我把這段時間使用poi的一些心得總結出來,希望能對和我遇到相同問題的朋友有所幫助,少熬幾個夜,多點時間陪MM:),至于poi基本的使用方法,自己去看文檔吧。

          1、設置分頁符的bug。

          poi里的HSSFSheet類提供了setRowBreak方法可以設置Sheet的分頁符。

          Bug:如果你要設置分頁符的Sheet是本來就有的,并且你沒有在里面插入過分頁符,那么調用setRowBreak時POI會拋出空指針的異常。

          解決方法:在Excel里給這個sheet插入一個分頁符,用POI打開后再把它刪掉,然后你就可以隨意插入分頁符了。

          如果sheet是由poi生成的則沒有這個問題。我跟蹤了setRowBreak的源代碼,發(fā)現是Sheet.java下的PageBreakRecord rowBreaks這個變量在搞鬼,如果Sheet里原來沒有分頁符,開發(fā)這個模塊的那位兄臺忘了為這個對象new實例,所以只能我們先手工給Excel插入一個分頁符來觸發(fā)poi為rowBreaks創(chuàng)建實例。

          2、如何拷貝行。

          我在gmane.org的poi用戶論壇翻遍了每個相關的帖子,找遍了api,也沒看到一個拷貝行的方法,沒辦法,只能自己寫:

          //注: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;
          }
          }
          }
          }

          這個函數有兩個問題暫時無法解決:

          a、只能在同一個Workbook里面使用,跨Workbook總是拷不過去,不知道為什么?

          b、由于在拷貝行時也把行高也拷過去了,如果往這些單元格里寫入的數據長度超過單元格長度,那么他們不會自動調整行高!

          有哪位大俠知道上面兩個問題任意一個的解決方法,請第一時間通知我!!!

          3、公式的問題。

          POI對Excel公式的支持是相當好的,但是我發(fā)現一個問題,如果公式里面的函數不帶參數,比如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論壇查相關帖子,得到兩種結論:1、不支持寫入圖片;2、支持寫入圖片,通過EscherGraphics2d這個Class實現。于是我就去查EscherGraphics2d這個Class,發(fā)現這個Class提供了N個drawImage方法,喜出望外的我開始寫代碼,結果調了一天,一直看不到效果,黔驢技窮的我在萬般無奈下只好跟蹤進drawImage這個函數內部,經過N個函數調用后在最底層函數發(fā)現了最終答案(偶當場暴走!!!):

          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;
          }
          所以我強烈建議大家,以后使用第三方開發(fā)包一定盡量下載它的源代碼,這樣你在碰到問題時,看看它的的內部是怎么實現的,很多時候就可以不必重蹈我的覆轍了。既然POI不能寫入圖片,那我們只能把目光投向JXL,我用JXL寫入圖片功能是實現了,付出的代價是now()和today()這些函數丟失掉了,魚與熊掌不能兼得吧,至于怎么解決JXL公式的問題,到下面這個帖子里和我一起守株待兔吧:

          http://community.csdn.net/Expert/topic/3569/3569340.xml?temp=.8480646

          好了我所知道得就這些,我接觸poi也才幾星期時間,上面有些內容可能說得并不正確,希望各位大蝦砸磚指正!

          posted on 2008-03-10 18:18 jinfeng_wang 閱讀(867) 評論(0)  編輯  收藏 所屬分類: javaZZ
          主站蜘蛛池模板: 阳曲县| 资兴市| 噶尔县| 齐齐哈尔市| 阿鲁科尔沁旗| 荣成市| 濮阳市| 鱼台县| 瑞金市| 和龙市| 台安县| 宁陕县| 梓潼县| 南康市| 东光县| 怀化市| 古交市| 江陵县| 额敏县| 陆川县| 航空| 渝中区| 凤台县| 梅州市| 游戏| 张家口市| 佛山市| 富顺县| 松原市| 南汇区| 寿光市| 太和县| 峡江县| 通州市| 洪洞县| 聂拉木县| 镇巴县| 常宁市| 平阳县| 通道| 罗定市|