Створення книги XLSX з нуля
XlsxWriter створює новий файл Excel .xlsx у пам’яті та записує його на диск або в байтовий буфер — без шаблону, без встановлення Excel, без COM-автоматизації. Це правильний інструмент, коли потрібен повний контроль над аркушами, клітинками, стилями, об’єднаннями та шириною стовпців, замість маппінгу через формат-незалежний IR.
Автор є частиною того самого ядра на Rust, яке читає XLSX із середнім часом 5,0 мс і 100 % рівнем успіху для дійсних файлів Office, і доступний у Python, Rust, Go, C# та JavaScript (нативний Node).
Як створити файл XLSX з нуля?
Створіть XlsxWriter, додайте аркуш, запишіть клітинки за координатами (row, col) (обидва з нуля) і викличте save. Значення клітинок можуть бути str, int, float, bool або None. Однаковий підхід працює в усіх прив’язках.
Rust
use office_oxide::xlsx::write::{XlsxWriter, CellData, CellStyle, NumberFormat};
fn main() -> office_oxide::Result<()> {
let mut wb = XlsxWriter::new();
let mut sheet = wb.add_sheet("Sales");
// Bold header row
let header = CellStyle::new().bold().background("D3D3D3");
sheet.set_cell_styled(0, 0, CellData::String("Item".into()), header.clone());
sheet.set_cell_styled(0, 1, CellData::String("Amount".into()), header);
// Data rows
sheet.set_cell(1, 0, CellData::String("Widget".into()));
sheet.set_cell(1, 1, CellData::Number(1500.0));
sheet.set_cell(2, 0, CellData::String("Gadget".into()));
sheet.set_cell(2, 1, CellData::Number(2400.0));
// SUM formula with currency formatting (omit the leading '=')
let currency = CellStyle::new().number_format(NumberFormat::Currency);
sheet.set_cell_styled(3, 1, CellData::Formula("SUM(B2:B3)".into()), currency);
// Merge a title banner across two columns
sheet.merge_cells(4, 0, 1, 2);
sheet.set_column_width(0, 20.0);
sheet.set_column_width(1, 15.0);
wb.save("sales.xlsx")?;
Ok(())
}
Python
from office_oxide import XlsxWriter
wb = XlsxWriter()
sheet = wb.add_sheet("Sales") # -> 0 (the sheet index)
# Header row — bold, light-grey fill
wb.set_cell_styled(sheet, 0, 0, "Item", bold=True, bg_color="D3D3D3")
wb.set_cell_styled(sheet, 0, 1, "Amount", bold=True, bg_color="D3D3D3")
# Data rows: row, col are 0-based
wb.set_cell(sheet, 1, 0, "Widget")
wb.set_cell(sheet, 1, 1, 1500.0)
wb.set_cell(sheet, 2, 0, "Gadget")
wb.set_cell(sheet, 2, 1, 2400.0)
# Widen the columns (Excel character units)
wb.set_column_width(sheet, 0, 20.0)
wb.set_column_width(sheet, 1, 15.0)
wb.save("sales.xlsx")
JavaScript
import { writeFileSync } from 'node:fs';
import { XlsxWriter } from 'office-oxide';
const wb = new XlsxWriter();
const sheet = wb.addSheet('Sales'); // 0-based index
// Header row — bold, grey fill (6-char hex string or null)
wb.setCellStyled(sheet, 0, 0, 'Item', true, 'D3D3D3');
wb.setCellStyled(sheet, 0, 1, 'Amount', true, 'D3D3D3');
// Data rows: value may be null, string, number, or boolean
wb.setCell(sheet, 1, 0, 'Widget');
wb.setCell(sheet, 1, 1, 1500.0);
wb.setCell(sheet, 2, 0, 'Gadget');
wb.setCell(sheet, 2, 1, 2400.0);
wb.mergeCells(sheet, 3, 0, 1, 2); // title banner: 1 row x 2 cols
wb.setColumnWidth(sheet, 0, 20.0);
wb.setColumnWidth(sheet, 1, 15.0);
wb.save('sales.xlsx');
// Or export to a Buffer:
const data = wb.toBytes();
writeFileSync('sales-copy.xlsx', data);
wb.close(); // release the native handle
Go
package main
import (
"os"
officeoxide "github.com/yfedoseev/office_oxide/go"
)
func main() {
wb := officeoxide.NewXlsxWriter()
defer wb.Close()
sheet := wb.AddSheet("Sales") // uint32, 0-based index
// Header row — bold with a grey fill
wb.SetCellStyled(sheet, 0, 0, "Item", true, "D3D3D3")
wb.SetCellStyled(sheet, 0, 1, "Amount", true, "D3D3D3")
// Data rows: value may be nil, string, float64, int, or bool
wb.SetCell(sheet, 1, 0, "Widget")
wb.SetCell(sheet, 1, 1, 1500.0)
wb.SetCell(sheet, 2, 0, "Gadget")
wb.SetCell(sheet, 2, 1, 2400.0)
wb.MergeCells(sheet, 3, 0, 1, 2) // title banner: 1 row x 2 cols
wb.SetColumnWidth(sheet, 0, 20.0)
wb.SetColumnWidth(sheet, 1, 15.0)
if err := wb.Save("sales.xlsx"); err != nil {
panic(err)
}
// Or export to bytes:
data, err := wb.ToBytes()
if err != nil {
panic(err)
}
_ = os.WriteFile("sales-copy.xlsx", data, 0o644)
}
C#
using OfficeOxide;
using var wb = new XlsxWriter();
uint sheet = wb.AddSheet("Sales"); // 0-based index
// Header row — bold, grey fill (6-char hex, no '#')
wb.SetCellStyled(sheet, 0, 0, "Item", bold: true, bgColor: "D3D3D3");
wb.SetCellStyled(sheet, 0, 1, "Amount", bold: true, bgColor: "D3D3D3");
// Data rows: value may be null, string, double, int, long, or bool
wb.SetCell(sheet, 1, 0, "Widget");
wb.SetCell(sheet, 1, 1, 1500.0);
wb.SetCell(sheet, 2, 0, "Gadget");
wb.SetCell(sheet, 2, 1, 2400.0);
wb.MergeCells(sheet, 3, 0, 1, 2); // title banner: 1 row x 2 cols
wb.SetColumnWidth(sheet, 0, 20.0);
wb.SetColumnWidth(sheet, 1, 15.0);
wb.Save("sales.xlsx");
// Or export to a byte[]:
byte[] data = wb.ToBytes();
File.WriteAllBytes("sales-copy.xlsx", data);
C
OfficeXlsxWriterHandle *w = office_xlsx_writer_new();
uint32_t s = office_xlsx_writer_add_sheet(w, "Sales"); /* 0-based index */
/* value_type in the writer: EMPTY=0, STRING=1, NUMBER=2 (no BOOLEAN) */
/* header row — bold + 6-char hex bg ("D3D3D3") or NULL */
office_xlsx_sheet_set_cell_styled(w, s, 0, 0, OFFICE_CELL_STRING, "Item", 0.0, true, "D3D3D3");
office_xlsx_sheet_set_cell_styled(w, s, 0, 1, OFFICE_CELL_STRING, "Amount", 0.0, true, "D3D3D3");
/* data rows */
office_xlsx_sheet_set_cell(w, s, 1, 0, OFFICE_CELL_STRING, "Widget", 0.0);
office_xlsx_sheet_set_cell(w, s, 1, 1, OFFICE_CELL_NUMBER, NULL, 1500.0);
office_xlsx_sheet_set_cell(w, s, 2, 0, OFFICE_CELL_STRING, "Gadget", 0.0);
office_xlsx_sheet_set_cell(w, s, 2, 1, OFFICE_CELL_NUMBER, NULL, 2400.0);
office_xlsx_sheet_merge_cells(w, s, 3, 0, 1, 2); /* title banner: row_span/col_span >= 1 */
office_xlsx_sheet_set_column_width(w, s, 0, 20.0); /* Excel char units */
office_xlsx_sheet_set_column_width(w, s, 1, 15.0);
int err = 0;
office_xlsx_writer_save(w, "sales.xlsx", &err);
/* or: uint8_t *b = office_xlsx_writer_to_bytes(w, &out_len, &err); ... office_oxide_free_bytes */
office_xlsx_writer_free(w);
Щоб передати байти у веб-відповідь або сховище об’єктів замість запису на диск, використовуйте to_bytes() (приклад на Python нижче):
Python
data = wb.to_bytes() # -> bytes (a complete .xlsx ZIP)
with open("sales.xlsx", "wb") as f:
f.write(data)
Сигнатури методів (Python)
| Метод | Сигнатура |
|---|---|
| Конструктор | XlsxWriter() |
| Додати аркуш | add_sheet(name: str) -> int |
| Задати клітинку | set_cell(sheet: int, row: int, col: int, value: None|str|bool|int|float) -> None |
| Задати стилізовану клітинку | set_cell_styled(sheet: int, row: int, col: int, value, bold: bool, bg_color: str|None = None) -> None |
| Об’єднати | merge_cells(sheet: int, row: int, col: int, row_span: int, col_span: int) -> None |
| Ширина стовпця | set_column_width(sheet: int, col: int, width: float) -> None |
| Зберегти | save(path) -> None |
| Експортувати | to_bytes() -> bytes |
add_sheet повертає індекс нового аркуша (з нуля) — передавайте його як аргумент sheet у всі інші виклики. Рядки та стовпці нумеруються з нуля: клітинка A1 — це (row=0, col=0), B1 — (row=0, col=1).
Як об’єднати клітинки та створити заголовний банер?
merge_cells(sheet, row, col, row_span, col_span) об’єднує прямокутний діапазон з якорем у (row, col). Обидва параметри span мають бути >= 1; значення об’єднаної клітинки береться з якірної клітинки.
Python
from office_oxide import XlsxWriter
wb = XlsxWriter()
s = wb.add_sheet("Report")
# A title that spans columns A through C of the first row
wb.set_cell_styled(s, 0, 0, "Q3 Revenue Report", bold=True, bg_color="FFE699")
wb.merge_cells(s, 0, 0, 1, 3) # 1 row tall, 3 columns wide
# Sub-header
wb.set_cell_styled(s, 1, 0, "Region", bold=True)
wb.set_cell_styled(s, 1, 1, "Q3", bold=True)
wb.set_cell_styled(s, 1, 2, "QoQ %", bold=True)
wb.set_cell(s, 2, 0, "NA")
wb.set_cell(s, 2, 1, 1_200_000)
wb.set_cell(s, 2, 2, 0.18)
wb.set_column_width(s, 0, 18.0)
wb.save("report.xlsx")
Сигнатури за мовами
Rust — крейт Rust надає більш повний будівник. add_sheet повертає позичений дескриптор SheetData, а клітинки приймають значення CellData (String, Number, Boolean, Formula або Empty) і необов’язковий CellStyle. CellStyle — це будівник, що підтримує bold(), italic(), background(), number_format(), align() тощо. Ключові сигнатури (на SheetData):
pub fn set_cell(&mut self, row: usize, col: usize, value: CellData) -> &mut Self
pub fn set_cell_styled(&mut self, row: usize, col: usize, value: CellData, style: CellStyle) -> &mut Self
pub fn merge_cells(&mut self, row: usize, col: usize, row_span: usize, col_span: usize) -> &mut Self
pub fn set_column_width(&mut self, col: usize, width: f64) -> &mut Self
На XlsxWriter: add_sheet(name: &str) -> SheetData<'_>, save(path) -> Result<()> і write_to<W: Write + Seek>(writer) -> Result<()> для запису в пам’ять. Також доступне індексне дзеркало (sheet_set_cell, sheet_set_cell_styled, sheet_merge_cells, sheet_set_column_width) — для тих, хто надає перевагу плоскій формі, як в інших прив’язках.
Python — XlsxWriter(), add_sheet(name: str) -> int, set_cell(sheet: int, row: int, col: int, value: None|str|bool|int|float) -> None, set_cell_styled(sheet: int, row: int, col: int, value, bold: bool, bg_color: str|None = None) -> None, merge_cells(sheet: int, row: int, col: int, row_span: int, col_span: int) -> None, set_column_width(sheet: int, col: int, width: float) -> None, save(path) -> None, to_bytes() -> bytes.
JavaScript — addSheet(name), setCell(sheet, row, col, value), setCellStyled(sheet, row, col, value, bold, bgColor = null), mergeCells(sheet, row, col, rowSpan, colSpan), setColumnWidth(sheet, col, width), save(path), toBytes(), close().
Go — NewXlsxWriter() *XlsxWriter, AddSheet(name string) uint32, SetCell(sheet, row, col uint32, value any), SetCellStyled(sheet, row, col uint32, value any, bold bool, bgColor string), MergeCells(sheet, row, col, rowSpan, colSpan uint32), SetColumnWidth(sheet, col uint32, width float64), Save(path string) error, ToBytes() ([]byte, error). Передайте "" як bgColor для відсутності заливки.
C# — AddSheet(string name) -> uint, SetCell(uint sheet, uint row, uint col, object? value), SetCellStyled(uint sheet, uint row, uint col, object? value, bool bold, string? bgColor = null), MergeCells(uint sheet, uint row, uint col, uint rowSpan, uint colSpan), SetColumnWidth(uint sheet, uint col, double width), Save(string path), ToBytes() -> byte[]. XlsxWriter реалізує IDisposable.
C — office_xlsx_writer_new() -> OfficeXlsxWriterHandle*, office_xlsx_writer_add_sheet(w, name) -> uint32_t, office_xlsx_sheet_set_cell(w, sheet, row, col, value_type, value_str, value_num), office_xlsx_sheet_set_cell_styled(w, sheet, row, col, value_type, value_str, value_num, bold, bg_color), office_xlsx_sheet_merge_cells(w, sheet, row, col, row_span, col_span), office_xlsx_sheet_set_column_width(w, sheet, col, width), office_xlsx_writer_save(w, path, &err), office_xlsx_writer_to_bytes(w, &out_len, &err), office_xlsx_writer_free(w). value_type: OFFICE_CELL_EMPTY (0), OFFICE_CELL_STRING (1) або OFFICE_CELL_NUMBER (2) — автор не має булевого типу клітинки.
Примітка: запис XLSX з нуля доступний у нативних прив’язках (Rust, Python, JavaScript/Node, Go, C#) і C ABI. Браузерна збірка WASM є лише для читання — класів автора немає — тому створюйте книги з одним із вищезазначених і передавайте байти потоком.
Довідник зі стилів
У прив’язках Python, Go, C#, JavaScript і C стилізований сеттер надає два параметри:
bold— булеве значення, що застосовує жирний шрифт до клітинки.bg_color/bgColor— 6-символьний RGB hex-рядок без ведучого#(наприклад,"D3D3D3"для світло-сірого,"FFE699"для бурштинового). ПередайтеNone/""/nullдля відсутності заливки.
Будівник CellStyle у Rust — найбільш повна поверхня: курсив, підкреслення, колір шрифту, розмір шрифту, назва шрифту, числові формати (General, Integer, Decimal2, Currency, Percent, Percent2, Date, DateTime), горизонтальне вирівнювання і перенос тексту. Інші прив’язки напряму надають лише два найпоширеніші параметри; для більш детального стилювання з цих мов використовуйте IR або виконайте постобробку.
Часті запитання
Рядки та стовпці нумеруються з нуля чи з одиниці?
І row, і col — цілі числа з нульовою нумерацією. Клітинка A1 — це (row=0, col=0), B1 — (row=0, col=1), A2 — (row=1, col=0). Індекс аркуша, що повертається add_sheet, також починається з нуля.
Чи потрібно встановлювати Excel або Microsoft Runtime?
Ні. XlsxWriter генерує дійсний OOXML .xlsx ZIP повністю на Rust. Немає COM-автоматизації, JVM і системних залежностей — той самий рушій читає XLSX із середнім часом 5,0 мс і 100 % рівнем успіху для дійсних файлів Office.
Як отримати файл у вигляді байтів замість запису на диск?
Викличте to_bytes() (Python/C#/JS) або ToBytes() (Go) — буде повернуто повний байтовий буфер .xlsx. У Rust використовуйте write_to(writer) з будь-яким Write + Seek-цільом, наприклад Cursor<Vec<u8>>. Це ідеально для HTTP-відповідей і завантаження в сховища об’єктів.
Чи можна записувати формули?
Так, у Rust через CellData::Formula("SUM(B2:B3)") (ведучий = опускається). Плоскі прив’язки (Python/Go/C#/JS) наразі підтримують рядкові, числові, булеві та порожні значення клітинок через set_cell.
Як додати другий робочий аркуш?
Знову викличте add_sheet — кожен виклик додає аркуш і повертає наступний індекс з нуля. Передавайте цей індекс як аргумент sheet у наступні виклики set_cell / merge_cells / set_column_width.
Дивіться також
- Створення документів з IR — одна схема, три цільові формати (DOCX/XLSX/PPTX)
- Редагування клітинок XLSX на місці — зміна клітинок у наявній книзі за допомогою
EditableDocument - Вилучення даних з XLSX — читання книги в структурований IR