Как вставить строку между двумя строками в существующем Excel с помощью HSSF (Apache POI) - PullRequest
50 голосов
/ 26 апреля 2011

Каким-то образом мне удается создать новые строки между двумя строками в существующем файле Excel.Проблема в том, что некоторые параметры форматирования не были включены при сдвиге строк.

Одним из них является то, что строки, которые являются скрытыми, относительно не проходят во время смены.Я имею в виду (например), строки от 20 до 30 скрыты, но при создании новых строк форматирование все еще там.Скрытые строки также должны перемещаться при вставке / создании новых строк, это должно быть от 21 до 31.

Другое дело, другой объект на листе, которого нет в ячейке.Как текстовое поле не двигаться после создания новой строки.Это как положение этих объектов фиксированы.Но я хочу, чтобы он двигался, так же, как я вставляю новую строку или вставляю строку в Excel.Если есть функция вставки новой строки, пожалуйста, дайте мне знать.

Это то, что у меня есть сейчас, просто фрагмент моего кода.

HSSFWorkbook wb = new HSSFWorkbook(template); //template is the source of file
HSSFSheet sheet = wb.getSheet("SAMPLE");
HSSFRow newRow;
HSSFCell cellData;

int createNewRowAt = 9; //Add the new row between row 9 and 10

sheet.shiftRows(createNewRowAt, sheet.getLastRowNum(), 1, true, false);
newRow = sheet.createRow(createNewRowAt);
newRow = sheet.getRow(createNewRowAt);

Если скопировать и вставитьСтроки возможны, что было бы большой помощью.Но я уже спрашиваю об этом здесь и не могу найти решение.Поэтому я решил создать строку в качестве временного решения.Я с этим покончил, но возникла такая проблема.

Любая помощь будет высоко ценится.Спасибо!

Ответы [ 8 ]

67 голосов
/ 26 апреля 2011

Вспомогательная функция для копирования постыдно адаптирована из здесь

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.util.CellRangeAddress;

import java.io.FileInputStream;
import java.io.FileOutputStream;

public class RowCopy {

    public static void main(String[] args) throws Exception{
        HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream("c:/input.xls"));
        HSSFSheet sheet = workbook.getSheet("Sheet1");
        copyRow(workbook, sheet, 0, 1);
        FileOutputStream out = new FileOutputStream("c:/output.xls");
        workbook.write(out);
        out.close();
    }

    private static void copyRow(HSSFWorkbook workbook, HSSFSheet worksheet, int sourceRowNum, int destinationRowNum) {
        // Get the source / new row
        HSSFRow newRow = worksheet.getRow(destinationRowNum);
        HSSFRow sourceRow = worksheet.getRow(sourceRowNum);

        // If the row exist in destination, push down all rows by 1 else create a new row
        if (newRow != null) {
            worksheet.shiftRows(destinationRowNum, worksheet.getLastRowNum(), 1);
        } else {
            newRow = worksheet.createRow(destinationRowNum);
        }

        // Loop through source columns to add to new row
        for (int i = 0; i < sourceRow.getLastCellNum(); i++) {
            // Grab a copy of the old/new cell
            HSSFCell oldCell = sourceRow.getCell(i);
            HSSFCell newCell = newRow.createCell(i);

            // If the old cell is null jump to next cell
            if (oldCell == null) {
                newCell = null;
                continue;
            }

            // Copy style from old cell and apply to new cell
            HSSFCellStyle newCellStyle = workbook.createCellStyle();
            newCellStyle.cloneStyleFrom(oldCell.getCellStyle());
            ;
            newCell.setCellStyle(newCellStyle);

            // If there is a cell comment, copy
            if (oldCell.getCellComment() != null) {
                newCell.setCellComment(oldCell.getCellComment());
            }

            // If there is a cell hyperlink, copy
            if (oldCell.getHyperlink() != null) {
                newCell.setHyperlink(oldCell.getHyperlink());
            }

            // Set the cell data type
            newCell.setCellType(oldCell.getCellType());

            // Set the cell data value
            switch (oldCell.getCellType()) {
                case Cell.CELL_TYPE_BLANK:
                    newCell.setCellValue(oldCell.getStringCellValue());
                    break;
                case Cell.CELL_TYPE_BOOLEAN:
                    newCell.setCellValue(oldCell.getBooleanCellValue());
                    break;
                case Cell.CELL_TYPE_ERROR:
                    newCell.setCellErrorValue(oldCell.getErrorCellValue());
                    break;
                case Cell.CELL_TYPE_FORMULA:
                    newCell.setCellFormula(oldCell.getCellFormula());
                    break;
                case Cell.CELL_TYPE_NUMERIC:
                    newCell.setCellValue(oldCell.getNumericCellValue());
                    break;
                case Cell.CELL_TYPE_STRING:
                    newCell.setCellValue(oldCell.getRichStringCellValue());
                    break;
            }
        }

        // If there are are any merged regions in the source row, copy to new row
        for (int i = 0; i < worksheet.getNumMergedRegions(); i++) {
            CellRangeAddress cellRangeAddress = worksheet.getMergedRegion(i);
            if (cellRangeAddress.getFirstRow() == sourceRow.getRowNum()) {
                CellRangeAddress newCellRangeAddress = new CellRangeAddress(newRow.getRowNum(),
                        (newRow.getRowNum() +
                                (cellRangeAddress.getLastRow() - cellRangeAddress.getFirstRow()
                                        )),
                        cellRangeAddress.getFirstColumn(),
                        cellRangeAddress.getLastColumn());
                worksheet.addMergedRegion(newCellRangeAddress);
            }
        }
    }
}
11 голосов
/ 22 августа 2012

Ссылка Ответ Qwerty , вы можете избежать раздувания размера XL, используя cellStyle.И когда тип CELL_TYPE_BLANK, getStringCellValue возвращает "" вместо null.

private static void copyRow(Sheet worksheet, int sourceRowNum, int destinationRowNum) {
  // Get the source / new row
  Row newRow = worksheet.getRow(destinationRowNum);
  Row sourceRow = worksheet.getRow(sourceRowNum);

  // If the row exist in destination, push down all rows by 1 else create a new row
  if (newRow != null) {
    worksheet.shiftRows(destinationRowNum, worksheet.getLastRowNum(), 1);
  } else {
    newRow = worksheet.createRow(destinationRowNum);
  }

  // Loop through source columns to add to new row
  for (int i = 0; i < sourceRow.getLastCellNum(); i++) {
    // Grab a copy of the old/new cell
    Cell oldCell = sourceRow.getCell(i);
    Cell newCell = newRow.createCell(i);

    // If the old cell is null jump to next cell
    if (oldCell == null) {
      newCell = null;
      continue;
    }

    // Use old cell style
    newCell.setCellStyle(oldCell.getCellStyle());

    // If there is a cell comment, copy
    if (newCell.getCellComment() != null) {
      newCell.setCellComment(oldCell.getCellComment());
    }

    // If there is a cell hyperlink, copy
    if (oldCell.getHyperlink() != null) {
      newCell.setHyperlink(oldCell.getHyperlink());
    }

    // Set the cell data type
    newCell.setCellType(oldCell.getCellType());

    // Set the cell data value
    switch (oldCell.getCellType()) {
    case Cell.CELL_TYPE_BLANK:
      break;
    case Cell.CELL_TYPE_BOOLEAN:
      newCell.setCellValue(oldCell.getBooleanCellValue());
      break;
    case Cell.CELL_TYPE_ERROR:
      newCell.setCellErrorValue(oldCell.getErrorCellValue());
      break;
    case Cell.CELL_TYPE_FORMULA:
      newCell.setCellFormula(oldCell.getCellFormula());
      break;
    case Cell.CELL_TYPE_NUMERIC:
      newCell.setCellValue(oldCell.getNumericCellValue());
      break;
    case Cell.CELL_TYPE_STRING:
      newCell.setCellValue(oldCell.getRichStringCellValue());
      break;
    }
  }
}
9 голосов
/ 15 мая 2018

Для людей, которые хотят вставить строку между двумя строками в существующем Excel с XSSF (Apache POI), в XSSFSheet уже реализован метод "copyRows".

import org.apache.poi.ss.usermodel.CellCopyPolicy;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class App2 throws Exception{
    public static void main(String[] args){
        XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream("input.xlsx"));
        XSSFSheet sheet = workbook.getSheet("Sheet1");
        sheet.copyRows(0, 2, 3, new CellCopyPolicy());
        FileOutputStream out = new FileOutputStream("output.xlsx");
        workbook.write(out);
        out.close();
    }
}
2 голосов
/ 20 апреля 2017

Ссылка Ответ Qwerty , если destRow не равен NULL, sheet.shiftRows () изменит ссылку destRow на следующую строку; поэтому мы всегда должны создавать новую строку:

if (destRow != null) {
  sheet.shiftRows(destination, sheet.getLastRowNum(), 1);
}
destRow = sheet.createRow(destination);
1 голос
/ 05 мая 2016

Я объединил некоторые другие ответы и комментарии в следующей реализации, протестированной с Apache POI v3.9.

У меня есть только один параметр rownum, потому что я сдвигаю целевую строку вниз и копирую ее вновая пустая строка.Формулы обрабатываются должным образом, они не копируются дословно, за одним исключением: ссылки на ячейки, которые выше скопированной строки, не обновляются;Обходной путь должен заменить эти явные ссылки (если таковые имеются) ссылками, рассчитанными с использованием INDIRECT(), как предложено в этом посте .

protected void copyRow(Sheet worksheet, int rowNum) {
    Row sourceRow = worksheet.getRow(rowNum);

    //Save the text of any formula before they are altered by row shifting
    String[] formulasArray = new String[sourceRow.getLastCellNum()];
    for (int i = 0; i < sourceRow.getLastCellNum(); i++) {
        if (sourceRow.getCell(i) != null && sourceRow.getCell(i).getCellType() == Cell.CELL_TYPE_FORMULA) 
            formulasArray[i] = sourceRow.getCell(i).getCellFormula();
    }

    worksheet.shiftRows(rowNum, worksheet.getLastRowNum(), 1);
    Row newRow = sourceRow;  //Now sourceRow is the empty line, so let's rename it
    sourceRow = worksheet.getRow(rowNum + 1);  //Now the source row is at rowNum+1

    // Loop through source columns to add to new row
    for (int i = 0; i < sourceRow.getLastCellNum(); i++) {
        // Grab a copy of the old/new cell
        Cell oldCell = sourceRow.getCell(i);
        Cell newCell;

        // If the old cell is null jump to next cell
        if (oldCell == null) {
            continue;
        } else {
            newCell = newRow.createCell(i);
        }

        // Copy style from old cell and apply to new cell
        CellStyle newCellStyle = worksheet.getWorkbook().createCellStyle();
        newCellStyle.cloneStyleFrom(oldCell.getCellStyle());
        newCell.setCellStyle(newCellStyle);

        // If there is a cell comment, copy
        if (oldCell.getCellComment() != null) {
            newCell.setCellComment(oldCell.getCellComment());
        }

        // If there is a cell hyperlink, copy
        if (oldCell.getHyperlink() != null) {
            newCell.setHyperlink(oldCell.getHyperlink());
        }

        // Set the cell data type
        newCell.setCellType(oldCell.getCellType());

        // Set the cell data value
        switch (oldCell.getCellType()) {
            case Cell.CELL_TYPE_BLANK:
                break;
            case Cell.CELL_TYPE_BOOLEAN:
                newCell.setCellValue(oldCell.getBooleanCellValue());
                break;
            case Cell.CELL_TYPE_ERROR:
                newCell.setCellErrorValue(oldCell.getErrorCellValue());
                break;
            case Cell.CELL_TYPE_FORMULA:
                newCell.setCellFormula(formulasArray[i]);
                break;
            case Cell.CELL_TYPE_NUMERIC:
                newCell.setCellValue(oldCell.getNumericCellValue());
                break;
            case Cell.CELL_TYPE_STRING:
                newCell.setCellValue(oldCell.getRichStringCellValue());
                break;
            default:   
                break; 
        }
    }

    // If there are any merged regions in the source row, copy to new row
    for (int i = 0; i < worksheet.getNumMergedRegions(); i++) {
        CellRangeAddress cellRangeAddress = worksheet.getMergedRegion(i);
        if (cellRangeAddress.getFirstRow() == sourceRow.getRowNum()) {
            CellRangeAddress newCellRangeAddress = new CellRangeAddress(newRow.getRowNum(),
                    (newRow.getRowNum() +
                            (cellRangeAddress.getLastRow() - cellRangeAddress.getFirstRow()
                                    )),
                    cellRangeAddress.getFirstColumn(),
                    cellRangeAddress.getLastColumn());
            worksheet.addMergedRegion(newCellRangeAddress);
        }
    }
}

Я использую эту реализацию в рабочем коде.

0 голосов
/ 07 марта 2018

Я реализовал это в Kotlin следующим образом:

fun Sheet.buildRow ( rowNum:Int ) : Row {
    val templateRow = this.getRow( rowNum )
    this.shiftRows( rowNum+1, sheet.lastRowNum, 1 )
    val newRow = this.createRow( rowNum+1 )
    templateRow.cellIterator().forEach {
        newRow.createCell( it.columnIndex ).cellStyle = it.cellStyle
    }
    return templateRow
}

Он не копирует значения ячеек, только формат. Должно быть применимо и к Java.

0 голосов
/ 02 марта 2017

Недавно я столкнулся с той же проблемой. Я должен был вставить новые строки в документ со скрытыми строками и столкнулся с теми же проблемами с вами. После некоторого поиска и некоторых электронных писем в списке Apache Poi, это похоже на ошибку в shiftrows (), когда в документе есть скрытые строки.

0 голосов
/ 12 сентября 2014

Что касается формул, которые «обновляются» в новой строке, так как все копирование происходит после сдвига, старая строка (теперь на один индекс выше новой строки) уже имеет свою формулу смещенную, поэтому копирование ее в новую row сделает новую строку ссылкой на старые ячейки строк. Решением было бы проанализировать формулы ДО сдвига, а затем применить их (простой массив String сделает эту работу. Я уверен, что вы можете закодировать это в несколько строк).

При запуске функции:

ArrayList<String> fArray = new ArrayList<String>();
Row origRow = sheet.getRow(sourceRow);
for (int i = 0; i < origRow.getLastCellNum(); i++) {
    if (origRow.getCell(i) != null && origRow.getCell(i).getCellType() == Cell.CELL_TYPE_FORMULA) 
        fArray.add(origRow.getCell(i).getCellFormula());
    else fArray.add(null);
}

Тогда при применении формулы к ячейке:

newCell.setCellFormula(fArray.get(i));
...