Не удается прочитать файл Excel 2010 с Apache POI. Номер первой строки равен -1

Я пытаюсь использовать этот testfile с API Apache POI (текущая версия 3 -10-ФИНАЛ). Следующий тестовый код

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

public class ExcelTest {

    public static void main(String[] args) throws Exception {
        String filename = "testfile.xlsx";
        XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(filename));
        XSSFSheet sheet = wb.getSheetAt(0);
        System.out.println(sheet.getFirstRowNum());
    }
}

приводит к тому, что номер первой строки равен -1 (и существующие строки возвращаются как нулевые). Тестовый файл был создан Excel 2010 (у меня нет контроля над этой частью) и может быть прочитан в Excel без предупреждений или проблем. Если я открою и сохраню файл в своей версии Excel (2013), его можно будет прочитать идеально, как и ожидалось.

Любые намеки на то, почему я не могу прочитать исходный файл или как я могу это сделать, очень ценятся.


person ratatosk    schedule 27.11.2014    source источник
comment
Это определенно не старый формат, для которого потребовалась бы структура HSSF. Я надеялся найти кого-нибудь, кто может сказать мне, что не так с файлом (потому что файлы 2010 года определенно могут быть прочитаны фреймворком)   -  person ratatosk    schedule 27.11.2014
comment
Вы уверены, что ваши данные не на листе 1 или листе 2?   -  person Gagravarr    schedule 27.11.2014
comment
Testfile.xlsx создается с помощью SpreadsheetGear 7.1.1.120. Откройте файл XLSX с помощью программного обеспечения, которое может работать с ZIP-архивами, и загляните в /xl/workbook.xml, чтобы увидеть это. В файлах worksheets/sheet?.xml следует заметить, что все элементы строки не имеют номеров строк. Если я помещу номер строки в первый тег строки, например <row r="1">, тогда POI apache сможет прочитать эту строку.   -  person Axel Richter    schedule 27.11.2014


Ответы (1)


Testfile.xlsx создается с помощью «SpreadsheetGear 7.1.1.120». Откройте файл XLSX с помощью программного обеспечения, которое может работать с ZIP-архивами, и просмотрите /xl/workbook.xml, чтобы увидеть это. В файлах worksheets/sheet?.xml следует заметить, что все элементы строки не имеют номеров строк. Если я помещу номер строки в первый тег строки, например <row r="1">, тогда POI apache сможет прочитать эту строку.

Если говорить о том, кто в этом виноват, то однозначно и Apache Poi, и SpreadsheetGear ;-). Apache POI, потому что атрибут r в элементе row является необязательным. Но SpreadsheetGear еще и потому, что нет причин не использовать атрибут r, если сам Excel когда-либо это делает.

Если вы не можете получить файл testfile.xlsx в формате, который Apache POI может считывать напрямую, вам придется работать с базовыми объектами. Следующее работает с вашим testfile.xlsx:

import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.InputStream;

import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetData;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;

import java.util.List;

class Testfile {

 public static void main(String[] args) {
  try {

   InputStream inp = new FileInputStream("testfile.xlsx");
   Workbook wb = WorkbookFactory.create(inp);

   Sheet sheet = wb.getSheetAt(0);

   System.out.println(sheet.getFirstRowNum());

   CTWorksheet ctWorksheet = ((XSSFSheet)sheet).getCTWorksheet();

   CTSheetData ctSheetData = ctWorksheet.getSheetData();

   List<CTRow> ctRowList = ctSheetData.getRowList();

   Row row = null;
   Cell[] cell = new Cell[2];

   for (CTRow ctRow : ctRowList) {
    row = new MyRow(ctRow, (XSSFSheet)sheet);
    cell[0] = row.getCell(0);
    cell[1] = row.getCell(1);
    if (cell[0] != null && cell[1] != null && cell[0].toString() != "" && cell[1].toString() != "") 
       System.out.println(cell[0].toString()+"\t"+cell[1].toString());
   }

  } catch (InvalidFormatException ifex) {
  } catch (FileNotFoundException fnfex) {
  } catch (IOException ioex) {
  }
 }
}

class MyRow extends XSSFRow {
 MyRow(org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow row, XSSFSheet sheet) {
  super(row, sheet);
 }
}

Я использовал:

  • org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet
  • org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetData
  • org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow

Которые являются частью двоичного дистрибутива Apache POI poi-bin-3.10.1-20140818 и находятся в пределах poi-ooxml-schemas-3.10.1-20140818.jar

Документацию см. на странице http://grepcode.com/snapshot/repo1.maven.org/maven2/org.apache.poi/ooxml-schemas/1.1/

И у меня есть расширение XSSFRow, потому что мы не можем использовать конструктор XSSFRow напрямую, так как он имеет защищенный доступ.

person Axel Richter    schedule 28.11.2014
comment
Просто чтобы уточнить отсутствие в SpreadsheetGear необязательного атрибута r, см. открытие файла xlsx, созданного с помощью электронной таблицы"> stackoverflow.com/questions/26634736/. Существует есть возможность указать SpreadsheetGear включить этот атрибут. Он не включен по умолчанию, потому что (кроме того факта, что он технически необязателен, и Excel не имеет проблем с чтением таких файлов), его исключение может значительно улучшить коэффициент сжатия zip и, следовательно, уменьшить размер файла, а также время его обработки. особенно для больших файлов книг. - person Tim Andersen; 22.01.2015