Данные строковых ячеек не отображаются в редакторе Excel, когда Excel создается с помощью SXSSFWorkbook и изменяется с помощью XSSFWorkbook - PullRequest
1 голос
/ 29 мая 2019

Сценарий:
1) CSV-файл преобразуется в файл Excel с помощью SXSSFWorkbook.2) Если данные снова считываются из CSV-файла и записываются в сгенерированный выше файл Excel с использованием XSSFWorkbook, тогда строковые данные не отображаются в libre office, но данные видны, если файл Excel открывается в онлайн-приложении Excel (некоторые из файлов Excel).зрители упоминают, что файл поврежден и данные могут быть восстановлены).

Создание ячейки с помощью SXSSFWorkbook:
Cell cell = row.createCell (1);
cell.setCellValue («Some Value»));

Обновление ячейки с использованием XSSFWorkbook:
Cell cell = row.getCell (1);
cell.setCellValue ("Some Value");

Замечания:
1) Когда значение ячейки обновляется с помощью XSSFCell, то исходное значение ячейки и строковое значение ячейки различаются.

2) Если файл Excel создается с помощью SXSSFWorkbook и открывается с использованием XSSFWorkbookтогда внутренне поддерживаемый STCellType является STCellType.INLINE_STR, и если файл Excel создается с использованием XSSFWorkbook, тогда внутренне поддерживаемый STCellType является STCellType.S (STCellTypeиспользуется в CTCell XSSFCell).

Apache POI Версия: 4.1.0

Пожалуйста, предложите решение.

1 Ответ

1 голос
/ 30 мая 2019

SXSSFWorkbook использует встроенные строки по умолчанию, а XSSFWorkbook использует таблицу общих строк по умолчанию.И XSSFCell.setCellValueImpl является неполным для встроенных строк.Он делает:

...
if(_cell.getT() == STCellType.INLINE_STR) {
 //set the 'pre-evaluated result
 _cell.setV(str.getString());
}
...

Так что для встроенных строк он всегда устанавливает v элемент, содержащий текст.Но встроенные строки также могут иметь элемент is, имеющий элемент t, содержащий текст, или даже элемент is, имеющий различные прогоны расширенного текста.Это не рассматривается с использованием XSSFCell.

Но SXSSFWorkbook может быть сконструирован так, что он также использует таблицу общих строк.Смотри конструктор SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize, boolean compressTmpFiles, boolean useSharedStringsTable).Поэтому, если используется следующий конструктор:

SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(new XSSFWorkbook(), 2, true, true);

, тогда никакие встроенные строки не используются, и последующее обновление с использованием XSSF не будет проблематичным.


Если SXSSFWorkbook не использует sharedтаблица строк, но встроенные строки, есть проблема при последующем обновлении ячеек с использованием XSSF из-за неполноты XSSFCell в использовании встроенных строк.Возможным обходным решением будет управление обновлением встроенных строк с помощью собственного кода.

Пример:

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

import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.xssf.streaming.*;

import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellType;

public class SXSSFTest {

 public static void main(String[] args) throws Exception {

  // first create SXSSFTest.xlsx using SXSSF ============================================

  String[][] data1 = new String[][]{
   new String[]{"A1", "B1", "C1"},
   new String[]{"A2", "B2", "C2"},
   new String[]{"A3", "B3", "C3"},
   new String[]{"A4", "B4", "C4"}
  };

  SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook();
  //SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(new XSSFWorkbook(), 2, true, true);

  SXSSFSheet sxssfSheet = sxssfWorkbook.createSheet();

  int r = 0;
  for (String[] rowValues : data1) {
   SXSSFRow row = sxssfSheet.createRow(r++);
   int c = 0;
   for (String value : rowValues) {
    SXSSFCell cell = row.createCell(c++);
    cell.setCellValue(value);
   }
  }

  FileOutputStream outputStream = new FileOutputStream("SXSSFTest.xlsx");
  sxssfWorkbook.write(outputStream);
  outputStream.close();
  sxssfWorkbook.dispose();
  sxssfWorkbook.close();

  // now reread the SXSSFTest.xlsx and update it using XSSF =============================

  String[][] data2 = new String[][]{
   new String[]{"A2 New", "B2 New", "C2 New"},
   new String[]{"A3 New", "B3 New", "C3 New"}
  };

  XSSFWorkbook xssfWorkbook = (XSSFWorkbook)WorkbookFactory.create(
                               new FileInputStream("SXSSFTest.xlsx"));

  XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(0);

  r = 1;
  for (String[] rowValues : data2) {
   XSSFRow row = xssfSheet.getRow(r++); if (row == null) row = xssfSheet.createRow(r++);
   int c = 0;
   for (String value : rowValues) {
    XSSFCell cell = row.getCell(c++); 
    if (cell != null) { // cell was already there
     if (cell.getCTCell().getT() == STCellType.INLINE_STR) { // cell has inline string in it
      if (cell.getCTCell().isSetIs()) { // inline string has is element
       cell.getCTCell().getIs().setT(value); // set t element in is element
      } else {
       cell.getCTCell().setV(value); // set v element of inline string
      }
     } else {
      cell.setCellValue(value); // set shared string cell value
     }
    } else {
     cell = row.createCell(c++);
     cell.setCellValue(value);
    }
   }
  }

  outputStream = new FileOutputStream("XSSFTest.xlsx");
  xssfWorkbook.write(outputStream);
  outputStream.close();   
  xssfWorkbook.close();

 }
}

После этого SXSSFTest.xlsx выглядит так в моем LibreOffice Calc:

enter image description here

Все ячейки имеют встроенные строки.

И XSSFTest.xlsx выглядит так:

enter image description here

Там все строковые строки теперь корректно обновляются.

LibreOffice
Version: 6.0.7.3
Build ID: 1:6.0.7-0ubuntu0.18.04.5
...