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

Sco*_*fen 0 groovy apache-poi

我是 groovy 的新手,我使用下面引用的 ExcelBuilder 代码遍历 Excel 电子表格以获取数据。在我迭代时是否容易写入数据?

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

value1,value2
Run Code Online (Sandbox Code Playgroud)

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

value1,value2,value3
Run Code Online (Sandbox Code Playgroud)

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

Sco*_*fen 5

是的,这是可以做到的!当我深入了解它的时候,我意识到我试图解决的问题与尝试同时从同一个文件中读取和写入不同,而是将 excel 数据存储在一个对象中我可以随时自由操纵。所以我添加了特定于我的需求的方法——这些方法可能满足也可能很多不满足其他人的需求——我把它们张贴在这里供更聪明的人挑选。最后,它现在正在做我想要它做的事情。

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

要查看我开始使用的代码及其工作原理的示例,请查看此博客条目

请注意,.save().saveAs()方法在保存后立即从保存的文件重新加载工作簿。这是 Apache POI 中似乎尚未修复的错误的解决方法(请参阅使用 apache poi 多次写入 xlsx 文档时的异常)。

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您看到任何明显的错误或改进方法(风格除外),我很乐意听取他们的意见。再说一次,Groovy 不是我有太多经验的语言,而且我已经好几年没有用 Java 做过任何事情了,所以我确信可能有一些更好的方法来做事。