Каковы ограничения (ошибки и ошибки) при использовании POI для создания книг Excel? - PullRequest
3 голосов
/ 09 марта 2009

Только что увидел сбой, когда мы превысили 255 столбцов. Возможно, этот вопрос должен быть направлен непосредственно на POI, но, скажем, я не хочу мешать им в их усилиях по дальнейшей разработке невероятно полезного API, которым он уже является. ;-) Страница ограничений не является детализированной.

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

Единственное ограничение, которое я могу быстро найти в интерфейсе POI, - ниже. Microsoft перечисляет дополнительные ограничения для Excel, которые, по-видимому, не охвачены POI.

РЕДАКТИРОВАТЬ: Упс. Только что понял, что мы не обновляли POI за последние 5 лет, поэтому с тех пор приведенный ниже код мог быть заменен 100 раз.

РЕДАКТИРОВАТЬ: с тех пор приведенный ниже код не изменился и версия 3.2 от 19 октября 2008 г.

/**
 * @throws RuntimeException if the bounds are exceeded.
 */
private void checkBounds(int cellNum) {
  if (cellNum > 255) {
      throw new RuntimeException("You cannot have more than 255 columns "+
                "in a given row (IV).  Because Excel can't handle it");
  }
  else if (cellNum < 0) {
      throw new RuntimeException("You cannot reference columns with an index of less then 0.");
  }
}

Ответы [ 7 ]

6 голосов
/ 26 июля 2009

Марлис, меня раздражает эта ошибка в poi framework, и я понял, что мне нужен styleManager. Эти посты заставляют меня чувствовать, что вся работа выполнена, пока я не приду к тому же выводу, что и вы. Я не хочу изобретать велосипед, поэтому я загружаю исходный код его фреймворка и ищу использование CellStyleManager.setCellStyle (). Дело в том, что в коде создаются два начальных объекта HSSFCellStyle, defaultCellStyle и cellStyle. Каждый раз, когда вы настраиваете стиль, используйте cellStyle, а затем с CellStyleManager установите его. Если стиль существует, он используется повторно, если нет, он создается. Любая другая попытка настроить другой стиль начинается с сброса cellStyle с использованием функции CellStyleHelper и defaultCellStyle, который остается нетронутым для всей программы. Таким образом, в конце вы получите на два стиля больше, чем нужно, но гораздо лучше, чем использовать другой API.

Как говорит Полгрег, код распространяется по всей структуре, но я объединяю весь код, необходимый только в двух классах. Я оставил их здесь до тех пор, пока не написал команде разработчиков paulgreg и poi, чтобы включить ее в банку, потому что я думаю, что для записи неизвестных данных в excel вам нужен такой менеджер.

изменения в основном в том, что менеджер знает рабочую книгу, предоставляет объект стиля и реализует код CellStyleHelper. (Они менее общие, потому что менеджеру необходимо знать рабочую книгу и, в целом, потому что вы должны использовать только вызов getGeneralStyle за раз (поскольку это один и тот же объект, он сбрасывается при любом вызове, но для общего использования используется код что подходит) Итак, чтобы использовать это:

... Creates a workbook
CellStyleManager styleManager = new CellStyleManager(workbook);
... Create a cell
HSSFCellStyle style = styleManager.getGeneralStyle();
styleManager.setCellStyle(cell, style); // no more 4000 styles error!

Код: Спасибо, ПолГрег!

// CellStyleCacheManager.java

public class CellStyleCacheManager {
    protected Set cellStyles;
    protected HSSFCellStyle cellStyle;
    protected HSSFCellStyle defaultValuesCellStyle;
    protected HSSFWorkbook workbook;

    public CellStyleCacheManager(HSSFWorkbook workbook) {
        this.workbook = workbook;
        this.cellStyles = new HashSet();
        // El desperdicio de estilos será pués de dos
        cellStyle = workbook.createCellStyle();
        // Estilo almacenado para reiniciar el que se va a usar
        defaultValuesCellStyle = workbook.createCellStyle();
    }

    /** Si el estilo se crea con createCellStyle, ya no podremos hacer nada */
    public void setCellStyle(HSSFCell cell, HSSFCellStyle cellStyle) {
        CellStyleWrapper cellStyleWrp = new CellStyleWrapper(cellStyle);
        CellStyleWrapper cachedCellStyleWrp = null;

        Iterator it = cellStyles.iterator();

        while(it.hasNext() && (cachedCellStyleWrp == null)) {
            CellStyleWrapper tmpCachedCellStyleWrp = (CellStyleWrapper) it.next();

            if(tmpCachedCellStyleWrp.equals(cellStyleWrp)) {
                // Si algún estilo coincide con el actual usamos ese
                cachedCellStyleWrp = tmpCachedCellStyleWrp;
            }
        }

        if(cachedCellStyleWrp == null) {
            // Si el estilo no existe creamos uno nuevo
            HSSFCellStyle newCellStyle = workbook.createCellStyle();
            CellStyleCacheManager.copyCellStyle(workbook, cellStyle, newCellStyle);

            CellStyleWrapper newWrp = new CellStyleWrapper(newCellStyle);
            cellStyles.add(newWrp);
            cachedCellStyleWrp = newWrp;
        }

        cell.setCellStyle(cachedCellStyleWrp.getHSSFCellStyle());
    }

    public HSSFCellStyle getGeneralStyle() {
        copyCellStyle(workbook, cellStyle, defaultValuesCellStyle);
        return cellStyle;
    }

    public static void copyCellStyle(HSSFWorkbook wb, HSSFCellStyle c1, HSSFCellStyle c2) {
        c2.setAlignment(c1.getAlignment());
        c2.setBorderBottom(c1.getBorderBottom());
        c2.setBorderLeft(c1.getBorderLeft());
        c2.setBorderRight(c1.getBorderRight());
        c2.setBorderTop(c1.getBorderTop());
        c2.setBottomBorderColor(c1.getBottomBorderColor());
        c2.setDataFormat(c1.getDataFormat());
        c2.setFillBackgroundColor(c1.getFillBackgroundColor());
        c2.setFillForegroundColor(c1.getFillForegroundColor());
        c2.setFillPattern(c1.getFillPattern());

        try {
            c2.setFont(wb.getFontAt(c1.getFontIndex()));
        } catch(NullPointerException e) {
            TLogger.getInstance().log(e.getMessage());
        } catch(ArrayIndexOutOfBoundsException e) {
            TLogger.getInstance().log("Be sure to have intialized all POI font objects !\n%s",e.getMessage());
        }

        c2.setHidden(c1.getHidden());
        c2.setIndention(c1.getIndention());
        c2.setLeftBorderColor(c1.getLeftBorderColor());
        c2.setLocked(c1.getLocked());
        c2.setRightBorderColor(c1.getRightBorderColor());
        c2.setRotation(c1.getRotation());
        c2.setTopBorderColor(c1.getTopBorderColor());
        c2.setVerticalAlignment(c1.getVerticalAlignment());
        c2.setWrapText(c1.getWrapText());
    }   
}

CellStyleWrapper.java

public class CellStyleWrapper implements Comparable {
    private HSSFCellStyle cs;
    private int hashCode;

    public CellStyleWrapper(HSSFCellStyle cs) {
        this.cs = cs;
    }

    public boolean equals(Object obj) {
        CellStyleWrapper csWrp_;
        HSSFCellStyle cs_;

        try {
            csWrp_ = (CellStyleWrapper) obj;
        } catch(ClassCastException e) {
            return false;
        }

        cs_ = csWrp_.getHSSFCellStyle();

        return (cs.getAlignment() == cs_.getAlignment()) && (cs.getBorderBottom() == cs_.getBorderBottom())
                && (cs.getBorderLeft() == cs_.getBorderLeft()) && (cs.getBorderRight() == cs_.getBorderRight())
                && (cs.getBorderTop() == cs_.getBorderTop())
                && (cs.getBottomBorderColor() == cs_.getBottomBorderColor())
                && (cs.getDataFormat() == cs_.getDataFormat())
                && (cs.getFillBackgroundColor() == cs_.getFillBackgroundColor())
                && (cs.getFillForegroundColor() == cs_.getFillForegroundColor())
                && (cs.getFillPattern() == cs_.getFillPattern()) && (cs.getFontIndex() == cs_.getFontIndex())
                && (cs.getHidden() == cs_.getHidden()) && (cs.getIndention() == cs_.getIndention())
                && (cs.getLeftBorderColor() == cs_.getLeftBorderColor()) && (cs.getLocked() == cs_.getLocked())
                && (cs.getRightBorderColor() == cs_.getRightBorderColor()) && (cs.getRotation() == cs_.getRotation())
                && (cs.getTopBorderColor() == cs_.getTopBorderColor())
                && (cs.getVerticalAlignment() == cs_.getVerticalAlignment())
                && (cs.getWrapText() == cs_.getWrapText());
    }

    private int v(int i) {
        if(i == 0) {
            return 1;
        } else {
            return i;
        }
    }

    public int hashCode() {
        if(hashCode == 0) {
            hashCode = 17;
            hashCode = 37 * v(cs.getBorderBottom());
            hashCode = 37 * v(cs.getBorderLeft());
            hashCode = 37 * v(cs.getBorderRight());
            hashCode = 37 * v(cs.getBorderTop());
            hashCode = 37 * v(cs.getBottomBorderColor());
            hashCode = 37 * v(cs.getDataFormat());
            hashCode = 37 * v(cs.getFillBackgroundColor());
            hashCode = 37 * v(cs.getFillForegroundColor());
            hashCode = 37 * v(cs.getFillPattern());
            hashCode = 37 * v(cs.getFontIndex());
            hashCode = 37 * (cs.getHidden() ? 1 : (-1));
            hashCode = 37 * v(cs.getIndention());
            hashCode = 37 * v(cs.getLeftBorderColor());
            hashCode = 37 * (cs.getLocked() ? 1 : (-1));
            hashCode = 37 * v(cs.getRightBorderColor());
            hashCode = 37 * v(cs.getRotation());
            hashCode = 37 * v(cs.getTopBorderColor());
            hashCode = 37 * v(cs.getVerticalAlignment());
            hashCode = 37 * (cs.getWrapText() ? 1 : (-1));
        }

        return hashCode;
    }

    public int compareTo(Object obj) {
        int diff = 0;
        CellStyleWrapper csWrp_;
        HSSFCellStyle cs_;

        try {
            csWrp_ = (CellStyleWrapper) obj;
        } catch(ClassCastException e) {
            return -1;
        }

        cs_ = csWrp_.getHSSFCellStyle();

        diff = cs.getAlignment() - cs_.getAlignment();

        if(diff != 0) {
            return diff;
        }

        diff = cs.getBorderBottom() - cs_.getBorderBottom();

        if(diff != 0) {
            return diff;
        }

        diff = cs.getBorderLeft() - cs_.getBorderLeft();

        if(diff != 0) {
            return diff;
        }

        diff = cs.getBorderRight() - cs_.getBorderRight();

        if(diff != 0) {
            return diff;
        }

        diff = cs.getBorderTop() - cs_.getBorderTop();

        if(diff != 0) {
            return diff;
        }

        diff = cs.getBottomBorderColor() - cs_.getBottomBorderColor();

        if(diff != 0) {
            return diff;
        }

        diff = cs.getDataFormat() - cs_.getDataFormat();

        if(diff != 0) {
            return diff;
        }

        diff = cs.getFillBackgroundColor() - cs_.getFillBackgroundColor();

        if(diff != 0) {
            return diff;
        }

        diff = cs.getFillForegroundColor() - cs_.getFillForegroundColor();

        if(diff != 0) {
            return diff;
        }

        diff = cs.getFillPattern() - cs_.getFillPattern();

        if(diff != 0) {
            return diff;
        }

        diff = cs.getFontIndex() - cs_.getFontIndex();

        if(diff != 0) {
            return diff;
        }

        if(cs.getHidden() != cs_.getHidden()) {
            return -1;
        }

        diff = cs.getIndention() - cs_.getIndention();

        if(diff != 0) {
            return diff;
        }

        diff = cs.getLeftBorderColor() - cs_.getLeftBorderColor();

        if(diff != 0) {
            return diff;
        }

        if(cs.getLocked() != cs_.getLocked()) {
            return -1;
        }

        diff = cs.getRightBorderColor() - cs_.getRightBorderColor();

        if(diff != 0) {
            return diff;
        }

        diff = cs.getRotation() - cs_.getRotation();

        if(diff != 0) {
            return diff;
        }

        diff = cs.getTopBorderColor() - cs_.getTopBorderColor();

        if(diff != 0) {
            return diff;
        }

        diff = cs.getVerticalAlignment() - cs_.getVerticalAlignment();

        if(diff != 0) {
            return diff;
        }

        if(cs.getWrapText() != cs_.getWrapText()) {
            return -1;
        }

        return 0;
    }

    public HSSFCellStyle getHSSFCellStyle() {
        return cs;
    }
}

Забавно, что в источнике poi, в комментариях HSSFCellStyle, есть эта запись

// Why would you do that??
protected HSSFCellStyle(...

4000 стилей ограничивают человека, Этого достаточно для разума?

3 голосов
/ 01 февраля 2011

Что касается ограничения на количество HSSFCellStyles в рабочей книге, я нашел более простой способ, чем создание менеджера стилей. Класс POI CellUtils имеет метод setCellStyleProperty (), который попытается найти стиль в книге и использовать его или создать, если он не существует.

В этом примере используется POI 3.7 для записи даты и используется только один формат для каждой ячейки даты (если все базовые ячейки имеют одинаковый стиль):

   public void writeFormattedDate(Workbook wb, Cell cell, Date date) {
            CellUtil.setCellStyleProperty(cell, wb, CellUtil.DATA_FORMAT, wb.getCreationHelper().createDataFormat().getFormat("dd-MMM-yyyy"));
            cell.setCellValue(date)
    }

Основным условием для setCellStyleProperty () является то, что вы можете установить только одно свойство за раз. Вы можете легко переписать его, чтобы взять список свойств и значений.

В моих тестах ограничение составило около 4030 стилей, а затем при открытии книги выдает ошибку и удаляет лишние форматы.

2 голосов
/ 09 марта 2009

Одно из самых больших ограничений, которые я обнаружил при использовании POI для записи файлов Excel, заключалось в том, что он сохраняет все содержимое файла в памяти до его записи в файл. Для очень больших файлов (много строк) это стало настоящей проблемой, что привело к частым исключениям OutOfMemory.

Однако, как и у вас, это было с очень старой версией POI. Я не уверен, что более новые версии используют память более эффективно.

1 голос
/ 26 августа 2009

@ albfan

Мне понравились ваши классы кеша и они были преобразованы в .NET. Я думаю, что нашел ошибку, хотя.

В getGeneralStyle () есть вызов copyCellStyle (рабочая книга, cellStyle, defaultValuesCellStyle) ;. Этот вызов копирует значения из объекта cellStyle в defaultValuesCellStyle, таким образом перезаписывая значения по умолчанию.

Я думаю, что мы хотим обратного, поэтому его следует изменить на: copyCellStyle (workbook, defaultValuesCellStyle, cellStyle);

1 голос
/ 30 апреля 2009

В paulgreg относительно вашего CellStyleCacheManager: Хотя это правда, что это способ повторного использования стилей, ваш метод setCellStyle () ожидает параметр HSSFCellStyle, и единственный известный мне способ создания HSSFCellStyle - это зарегистрировать его в книге, вызвав его метод createCellStyle ().

Хотя ячейки на самом деле используют меньше стилей, разве вы не получите такое же количество стилей, зарегистрированных в книге, как и без кеша? Или есть какая-то чистка неиспользованных стилей в HSSF, о которой я не знаю?

1 голос
/ 19 марта 2009

Другое серьезное ограничение (на мой взгляд, не очень хорошо объясненное) заключается в том, что HSSFCellStyle ограничен внутри рабочей книги (я думаю, что это ограничение Excel).

Вы не должны создавать новый стиль в каждой ячейке (потому что в этом случае Excel не сможет открыть вашу рабочую книгу), но вы должны сохранять ссылку на них и повторно применять их, когда стиль ячейки похож.

Итак, вам придется управлять внутренним кешем HSSFCellStyle, например, таким: CellStyleCacheManager .

0 голосов
/ 27 июля 2009

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

...