<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    jinfeng_wang

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

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


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

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

    現(xiàn)在我要做的東西基本完成啦,我把這段時(shí)間使用poi的一些心得總結(jié)出來(lái),希望能對(duì)和我遇到相同問(wèn)題的朋友有所幫助,少熬幾個(gè)夜,多點(diǎn)時(shí)間陪MM:),至于poi基本的使用方法,自己去看文檔吧。

    1、設(shè)置分頁(yè)符的bug。

    poi里的HSSFSheet類(lèi)提供了setRowBreak方法可以設(shè)置Sheet的分頁(yè)符。

    Bug:如果你要設(shè)置分頁(yè)符的Sheet是本來(lái)就有的,并且你沒(méi)有在里面插入過(guò)分頁(yè)符,那么調(diào)用setRowBreak時(shí)POI會(huì)拋出空指針的異常。

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

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

    2、如何拷貝行。

    我在gmane.org的poi用戶(hù)論壇翻遍了每個(gè)相關(guān)的帖子,找遍了api,也沒(méi)看到一個(gè)拷貝行的方法,沒(méi)辦法,只能自己寫(xiě):

    //注:this.fWorkbook是一個(gè)HSSHWorkbook,請(qǐng)自行在外部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);
    }
    }
    //設(shè)置列寬
    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;
    }
    }
    //拷貝行并填充數(shù)據(jù)
    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這個(gè)函數(shù)的用途在后面說(shuō)明
    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;
    }
    }
    }
    }

    這個(gè)函數(shù)有兩個(gè)問(wèn)題暫時(shí)無(wú)法解決:

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

    b、由于在拷貝行時(shí)也把行高也拷過(guò)去了,如果往這些單元格里寫(xiě)入的數(shù)據(jù)長(zhǎng)度超過(guò)單元格長(zhǎng)度,那么他們不會(huì)自動(dòng)調(diào)整行高!

    有哪位大俠知道上面兩個(gè)問(wèn)題任意一個(gè)的解決方法,請(qǐng)第一時(shí)間通知我!!!

    3、公式的問(wèn)題。

    POI對(duì)Excel公式的支持是相當(dāng)好的,但是我發(fā)現(xiàn)一個(gè)問(wèn)題,如果公式里面的函數(shù)不帶參數(shù),比如now()或today(),那么你通過(guò)getCellFormula()取出來(lái)的值就是now(ATTR(semiVolatile))和today(ATTR(semiVolatile)),這樣的值寫(xiě)入Excel是會(huì)出錯(cuò)的,這也是我上面copyRow的函數(shù)在寫(xiě)入公式前要調(diào)用parseFormula的原因,parseFormula這個(gè)函數(shù)的功能很簡(jiǎn)單,就是把ATTR(semiVolatile)刪掉,我把它的代碼貼出來(lái):
    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();
    }
    至于為什么會(huì)出現(xiàn)ATTR(semiVolatile),希望哪位大俠現(xiàn)身跟我解釋一下。

    4、向Excel寫(xiě)入圖片的問(wèn)題。

    我上poi論壇查相關(guān)帖子,得到兩種結(jié)論:1、不支持寫(xiě)入圖片;2、支持寫(xiě)入圖片,通過(guò)EscherGraphics2d這個(gè)Class實(shí)現(xiàn)。于是我就去查EscherGraphics2d這個(gè)Class,發(fā)現(xiàn)這個(gè)Class提供了N個(gè)drawImage方法,喜出望外的我開(kāi)始寫(xiě)代碼,結(jié)果調(diào)了一天,一直看不到效果,黔驢技窮的我在萬(wàn)般無(wú)奈下只好跟蹤進(jìn)drawImage這個(gè)函數(shù)內(nèi)部,經(jīng)過(guò)N個(gè)函數(shù)調(diào)用后在最底層函數(shù)發(fā)現(xiàn)了最終答案(偶當(dāng)場(chǎng)暴走!!!):

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

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

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

    posted on 2008-03-10 18:18 jinfeng_wang 閱讀(869) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): javaZZ
    主站蜘蛛池模板: 永久免费AV无码国产网站| 亚洲高清视频在线播放| 毛片免费vip会员在线看| a级片免费在线播放| 特级aaaaaaaaa毛片免费视频| 亚洲欧洲日韩在线电影| 亚洲国产精品无码久久久蜜芽| 亚洲AⅤ视频一区二区三区| 成人免费午夜视频| 性短视频在线观看免费不卡流畅| 久久国产乱子伦精品免费不卡| 亚欧洲精品在线视频免费观看| 国产亚洲Av综合人人澡精品| 亚洲国产乱码最新视频| 亚洲精品乱码久久久久久下载| 亚洲av无码精品网站| 亚洲乱码精品久久久久..| 亚洲一区二区三区免费| www.亚洲精品.com| 免费人成在线观看网站品爱网日本| 在线观看无码的免费网站| 中文字幕无码免费久久99| 亚洲免费福利视频| 亚欧人成精品免费观看| 久久99国产乱子伦精品免费| 日韩午夜理论免费TV影院| 日韩视频免费在线观看| 男人进去女人爽免费视频国产| 日本免费久久久久久久网站| 13小箩利洗澡无码视频网站免费| 国产在线国偷精品免费看| 中文字幕乱码系列免费| 你懂的免费在线观看| 99久久免费国产特黄| 国产在线播放线91免费| 一区二区免费视频| 久久久久av无码免费网| 成全视频在线观看免费高清动漫视频下载 | g0g0人体全免费高清大胆视频| 日日躁狠狠躁狠狠爱免费视频 | 亚洲自偷自拍另类图片二区|