Groovy和POI:我可以同时读/写吗?

时间:2012-01-27 22:00:20

标签: groovy apache-poi

我是groovy的新手,我使用下面引用的ExcelBuilder代码迭代excel电子表格来获取数据。我迭代时是否有一个易于编写的数据?

例如,第1行可能包含这样的数据(CSV):

value1,value2

在迭代之后,我希望它看起来像这样:

value1,value2,value3

http://www.technipelago.se/content/technipelago/blog/44

1 个答案:

答案 0 :(得分:4)

是的,这可以做到!当我深入了解它时,我意识到我试图解决的问题与尝试同时从同一个文件读取和写入的问题不同,而是excel数据存储在一个我可以随意操作的对象中。所以我添加了特定于我的需求的方法 - 可能或许多不能满足其他人的需求 - 我在这里发布它们以供更聪明的人分开。最后,它正在做我想做的事。

我添加了一个单元格方法,该方法采用索引(数字或标签)和一个值,该值将更新上下文中当前行的单元格(特别是在使用.eachLine()时)和.putRow()方法这会在指定的电子表格中添加整行。它还处理Excel 2003,2007和2010格式。当引用的文件,工作表或单元格不存在时,将创建它们。由于我的源电子表格通常有公式和图表可以显示我输入的数据,因此.save().saveAs()方法会在保存之前调用.evaluateAllFormulaCells()

要查看我开始使用的代码及其工作原理示例,请查看this blog entry

请注意,.save().saveAs()方法都会在保存后立即从保存的文件中重新加载工作簿。这是针对Apache POI中的一个错误的解决方法,似乎尚未解决(请参阅Exception when writing to the xlsx document several times using apache poi)。

import groovy.lang.Closure;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;

class Excel
{
    def workbook;
    def sheet;
    def labels;
    def row;
    def infilename;
    def outfilename;

    Excel(String fileName)
    {
        HSSFRow.metaClass.getAt = {int index ->
            def cell = delegate.getCell(index);
            if(! cell)
            {
                return null;
            }

            def value;

            switch (cell.cellType)
            {
                case HSSFCell.CELL_TYPE_NUMERIC:
                    if(HSSFDateUtil.isCellDateFormatted(cell))
                    {
                        value = cell.dateCellValue;
                    }
                    else
                    {
                        value = new DataFormatter().formatCellValue(cell);
                    }
                    break;
                case HSSFCell.CELL_TYPE_BOOLEAN:
                    value = cell.booleanCellValue
                    break;
                default:
                    value = new DataFormatter().formatCellValue(cell);
                    break;
            }

            return value
        }

        XSSFRow.metaClass.getAt = {int index ->
            def cell = delegate.getCell(index);
            if(! cell)
            {
                return null;
            }
            def value = new DataFormatter().formatCellValue(cell);

            switch (cell.cellType)
            {
                case XSSFCell.CELL_TYPE_NUMERIC:
                    if (DateUtil.isCellDateFormatted(cell))
                    {
                        value = cell.dateCellValue;
                    }
                    else
                    {
                        value = new DataFormatter().formatCellValue(cell);
                    }
                    break;
                case XSSFCell.CELL_TYPE_BOOLEAN:
                    value = cell.booleanCellValue
                    break;
                default:
                    value = new DataFormatter().formatCellValue(cell);
                    break;
            }

            return value;
        }

        infilename = fileName;
        outfilename = fileName;

        try
        {
            workbook = WorkbookFactory.create(new FileInputStream(infilename));
        }
        catch (FileNotFoundException e)
        {
            workbook = (infilename =~ /(?is:\.xlsx)$/) ?  new XSSFWorkbook() : new HSSFWorkbook();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    def getSheet(index)
    {
        def requested_sheet;

        if(!index) index = 0;

        if(index instanceof Number)
        {
            requested_sheet = (workbook.getNumberOfSheets >= index) ? workbook.getSheetAt(index) : workbook.createSheet();
        }
        else if (index ==~ /^\d+$/)
        {
            requested_sheet = (workbook.getNumberOfSheets >= Integer.valueOf(index)) ? workbook.getSheetAt(Integer.valueOf(index)) : workbook.createSheet();
        }
        else
        {
            requested_sheet = (workbook.getSheetIndex(index) > -1) ? workbook.getSheet(index) : workbook.createSheet(index);
        }

        return requested_sheet;
    }

    def cell(index)
    {
        if (labels && (index instanceof String))
        {
            index = labels.indexOf(index.toLowerCase());
        }

        if (row[index] == null)
        {
            row.createCell(index);
        }

        return row[index];
    }

    def cell(index, value)
    {
        if (labels.indexOf(index.toLowerCase()) == -1)
        {
            labels.push(index.toLowerCase());

            def frow  = sheet.getRow(0);
            def ncell = frow.createCell(labels.indexOf(index.toLowerCase()));
            ncell.setCellValue(index.toString());
        }

        def cell = (labels && (index instanceof String)) ? row.getCell(labels.indexOf(index.toLowerCase())) : row.getCell(index);

        if (cell == null)
        {
            cell = (index instanceof String) ? row.createCell(labels.indexOf(index.toLowerCase())) : row.createCell(index);
        }

        cell.setCellValue(value);
    }

    def putRow (sheetName, Map values = [:])
    {
        def requested_sheet = getSheet(sheetName);
        if (requested_sheet)
        {
            def lrow;
            if (requested_sheet.getPhysicalNumberOfRows() == 0)
            {
                lrow = requested_sheet.createRow(0);
                def lcounter = 0;
                values.each {entry->
                    def lcell = lrow.createCell(lcounter);
                    lcell.setCellValue(entry.key);
                    lcounter++;
                }
            }
            else
            {
                lrow = requested_sheet.getRow(0);
            }

            def sheetLabels = lrow.collect{it.toString().toLowerCase()}
            def vrow = requested_sheet.createRow(requested_sheet.getLastRowNum() + 1);
            values.each {entry->
                def vcell = vrow.createCell(sheetLabels.indexOf(entry.key.toLowerCase()));
                vcell.setCellValue(entry.value);
            }
        }
    }

    def propertyMissing(String name)
    {
        cell(name);
    }

    def propertyMissing(String name, value)
    {
        cell(name, value);
    }

    def eachLine (Map params = [:], Closure closure)
    {
        /*
         * Parameters:
         * skiprows    : The number of rows to skip before the first line of data and/or labels
         * offset      : The number of rows to skip (after labels) before returning rows
         * max         : The maximum number of rows to iterate
         * sheet       : The name (string) or index (integer) of the worksheet to use
         * labels      : A boolean to treat the first row as a header row (data can be reference by label)
         *
         */
        def skiprows = params.skiprows ?: 0;
        def offset = params.offset ?: 0;
        def max = params.max ?: 9999999;
        sheet = getSheet(params.sheet);
        def rowIterator = sheet.rowIterator();
        def linesRead = 0;

        skiprows.times{ rowIterator.next() }

        if(params.labels)
        {
            labels = rowIterator.next().collect{it.toString().toLowerCase()}
        }

        offset.times{ rowIterator.next() }

        closure.setDelegate(this);

        while(rowIterator.hasNext() && linesRead++ < max)
        {
            row = rowIterator.next();
            closure.call(row);
        }
    }

    def save ()
    {
        if (workbook.getClass().toString().indexOf("XSSF") > -1)
        {
            XSSFFormulaEvaluator.evaluateAllFormulaCells((XSSFWorkbook) workbook);
        }
        else
        {
            HSSFFormulaEvaluator.evaluateAllFormulaCells((HSSFWorkbook) workbook);
        }

        if (outfilename != null)
        {
            try
            {
                FileOutputStream output = new FileOutputStream(outfilename);
                workbook.write(output);
                output.close();

                workbook = null;
                workbook = WorkbookFactory.create(new FileInputStream(outfilename));
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

    def saveAs (String fileName)
    {
        if (workbook.getClass().toString().indexOf("XSSF") > -1)
        {
            XSSFFormulaEvaluator.evaluateAllFormulaCells((XSSFWorkbook) workbook);
        }
        else
        {
            HSSFFormulaEvaluator.evaluateAllFormulaCells((HSSFWorkbook) workbook);
        }

        try
        {
            FileOutputStream output = new FileOutputStream(fileName);
            workbook.write(output);
            output.close();
            outfilename = fileName;

            workbook = null;
            workbook = WorkbookFactory.create(new FileInputStream(outfilename));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}

如果你看到任何明显的错误或改进的方法(除了风格),我很乐意听到它们。同样,Groovy不是我经验丰富的语言,几年后我没有用Java做任何事情,所以我相信可能有更好的方法来做事。