Workbook and Sheet

Workbook is the root of the object model and the owner of the native handle. Everything else — sheets, ranges, cells, content objects — is reached from it, and is only valid while it is open.

Lifecycle

try (Workbook wb = Workbook.create()) {
    ...
}

Workbook implements AutoCloseable. Closing it releases the native memory holding the entire book. Any Sheet, Range, or Cell obtained from a workbook becomes invalid once it is closed — these are lightweight views onto the native model, not detached copies. Do not let them escape the try-with-resources block.

Leaking a workbook leaks native memory that the Java garbage collector cannot reclaim on your behalf, so a long-running service that opens workbooks per request must close every one of them.

Creating and opening

Call Purpose
Workbook.create() An empty workbook with no sheets — add one with createSheet
Workbook.createColumnar() Empty, using the columnar storage backend — see Streaming
Workbook.open(Path) Open a file; format inferred from the extension
Workbook.open(Path, String password) Open an encrypted file
Workbook.openBytes(byte[], String format) Open from memory
Workbook.openBytes(byte[], String format, String password) Open encrypted, from memory
Workbook.open(InputStream, String format) Open from a stream

The format argument is a lowercase extension: "xlsx", "xlsm", "xlsb", "xls", "ods", "csv", "json".

Sheets

int n = wb.sheetCount();
Sheet first = wb.sheet(0);
Sheet named = wb.sheet("Summary");

Sheet added = wb.createSheet("Q4");
Sheet inserted = wb.insertSheet(1, "Notes");
wb.renameSheet(1, "Appendix");
wb.moveSheet(1, 3);
wb.deleteSheet(3);

wb.setActiveSheet(0);
Sheet active = wb.activeSheet();

Sheet indices are 0-based and shift when sheets are inserted, deleted, or moved. In 1.0.0 builds, a held Sheet continues to refer to the same tab and its index() changes with the tab. In 0.1.0 builds a Sheet is bound to its old index instead, so re-fetch it by name after a structural sheet operation there.

Sheet properties

Sheet sheet = wb.sheet(0);

sheet.name();
sheet.index();
sheet.sheetType();                   // WORKSHEET, CHART, DIALOG, MACRO_SHEET, …
sheet.uniqueId();                    // stable across renames

sheet.setVisibility(Visibility.VERY_HIDDEN);
sheet.setTabColor(Color.rgb(0xC0, 0x39, 0x2B));
sheet.setRightToLeft(true);

uniqueId() is the identifier to key your own data off, not name() — a rename changes the name but not the id.

Headers, footers, and page setup

sheet.setHeader("&C&\"Calibri,Bold\"Quarterly Report");
sheet.setFooter("&LPrinted &D&RPage &P of &N");

sheet.setDifferentFirst(true);
sheet.setFirstHeader("&CCover");

sheet.setDifferentOddEven(true);
sheet.setEvenHeader("&L&F");

The &-codes are Excel’s header/footer codes: &C centre, &L left, &R right, &P page number, &N page count, &D date, &F filename.

Rows and columns

sheet.setRowHeight(0, 28.0);          // points
sheet.setColumnWidth(0, 24.0);        // character units, as in Excel
sheet.setDefaultRowHeight(15.0);
sheet.setDefaultColumnWidth(8.43);

sheet.insertRows(10, 3);
sheet.deleteRows(10, 3);
sheet.insertColumns(4, 1);
sheet.deleteColumns(4, 1);

sheet.freezePanes(1, 0);              // freeze the first row
sheet.setAutoFilter(sheet.range("A1:F1"));

Row height is in points; column width is in Excel’s character units (the width of the ‘0’ glyph in the default font), which is why the two use different scales. isRowHeightCustom(row) and isColumnWidthCustom(col) distinguish an authored size from an inherited default — relevant when you are deciding whether to auto-fit.

Inserting and deleting rows or columns adjusts what references the shifted area, on every sheet: formulas (including references from other sheets), merged regions, named ranges, conditional formats, validations, tables, chart series, the print area, and anchored objects.

0.1.0 builds adjusted only same-sheet formulas and merged regions; references from other sheets, names, conditional formats, validations, chart series, and the print area kept their old ranges.

Workbook settings

wb.setCalcMode(CalcMode.MANUAL);
wb.setIterativeCalc(true, 100, 0.001);
wb.setDate1904(false);

setDate1904(true) switches to the 1904 date system used by legacy Mac workbooks. Changing it on a workbook that already holds dates reinterprets those serial numbers — set it before populating dates, not after.

Chart sheets

A chart sheet is a sheet whose entire body is one chart:

int index = wb.addChartSheet("Revenue", chart);   // position among chart sheets
ChartView view = wb.chartSheetChart(index);
wb.removeChartSheet(index);

The chart-sheet methods take a chart sheet’s position among the chart sheets, not its index among all sheets.

See Charts.

Named ranges

wb.addName("TaxRate", "Config!$B$2");            // workbook-scoped
wb.addName("Local", "$A$1:$A$10", wb.sheet(0));  // scoped to one sheet

for (NamedRange nr : wb.names()) {
    System.out.println(nr.name() + " = " + nr.formula()
            + (nr.isWorkbookScoped() ? " (workbook)" : " (sheet " + nr.sheetScope() + ")"));
}

Range r = wb.findName("TaxRate").asRange();
wb.removeName("Local");

A name’s definition is a formula, not just a reference, so addName also covers constants ("=0.05") and expressions. asRange() only succeeds when the definition resolves to a contiguous area.

Named ranges are adjusted by structural edits like any other reference, which makes them the durable way to point at a region a user may move.

Next

Get code at GitHub