别再与 Apache POI 纠缠——认识 Sheetz,这个 Java 的一行代码 Excel 库

发布: (2026年2月18日 GMT+8 13:18)
7 分钟阅读
原文: Dev.to

Source: Dev.to

如果你曾经在 Java 中处理 Excel 文件,你一定很熟悉以下流程:

  • 引入 Apache POI。
  • 为了读取一列标题而编写数十行的样板代码。
  • 接下来花一个小时调试第 14 行的 NullPointerException,因为有人留下了空单元格。

听起来很熟悉吧?

Sheetz 是一个开源的 Java 库,它将所有这些痛苦压缩成一行代码:

List products = Sheetz.read("products.xlsx", Product.class);

没有样板代码。没有繁琐的步骤。只有数据。

为什么选择 Sheetz?

Apache POI 功能强大,但它并非为开发者的易用性而设计。
EasyExcel、FastExcel 和 Poiji 更好,但仍然需要相当多的配置。

Sheetz 采用不同的理念:默认零配置,需要时可完全控制

开箱即用功能

特性
🚀单行 API – Sheetz.read()Sheetz.write(),搞定
📊真正的 SAX 流式处理 – 使用约 10 MB 恒定内存处理百万行文件
🔄自动类型转换 – 19 个内置转换器(日期、枚举、BigDecimalUUID,……)
🧵线程安全 – 可安全并发使用
内置校验 – 提供带行/列上下文的详细错误报告
📝注解映射 – @Column 用于自定义表头、必填字段、默认值等

依赖

Maven

io.github.chitralabs.sheetz
sheetz-core
1.0.1

Gradle

implementation 'io.github.chitralabs.sheetz:sheetz-core:1.0.1'

简单 POJO

public class Product {
    public String name;
    public Double price;
    public Boolean inStock;
    public LocalDate releaseDate;

    public Product() {} // Required no‑arg constructor
}

读取与写入

// 读取 Excel
List products = Sheetz.read("products.xlsx", Product.class);

// 读取 CSV
List productsCsv = Sheetz.read("products.csv", Product.class);

// 没有模型?读取为映射
List<Map<String, Object>> data = Sheetz.readMaps("products.xlsx");

// 写入 Excel
Sheetz.write(products, "output.xlsx");

// 写入 CSV
Sheetz.write(products, "output.csv");

流式处理 – 常量内存

处理包含 1 百万行 的文件?使用 stream(),内存保持在约 10 MB,文件大小如何都不受影响。

// Process row‑by‑row – constant memory
Sheetz.stream("huge-file.xlsx", Product.class)
      .forEach(product -> process(product));

// Process in batches – perfect for bulk DB inserts
Sheetz.stream("huge-file.xlsx", Product.class)
      .batch(1000)
      .forEach(batch -> database.bulkInsert(batch));

// Full Java Streams support
long count = Sheetz.stream("huge-file.xlsx", Product.class)
                   .stream()
                   .filter(p -> p.price > 100)
                   .count();

⚠️ 经验法则: 对于超过 100 K 行 的文件,始终使用 stream()。在百万行文件上使用 read() 加载全部内容会很快触发 OutOfMemoryError

@Column – 灵活映射

标题与字段名不匹配?列顺序奇怪?需要为空单元格提供默认值?@Column 全面搞定。

public class Product {

    @Column("Product Name")               // Map to a different header
    public String name;

    @Column(index = 1)                     // Map by column index (0‑based)
    public Double price;

    @Column(required = true)               // Fail validation if empty
    public String sku;

    @Column(defaultValue = "pending")     // Default for empty cells
    public String status;

    @Column(format = "dd/MM/yyyy")         // Custom date format
    public LocalDate orderDate;

    @Column(converter = MoneyConverter.class) // Custom converter
    public BigDecimal amount;

    @Column(ignore = true)                // Skip this field entirely
    public String internalId;

    @Column(width = 20)                    // Column width in chars (write‑only)
    public String description;
}

带丰富错误详情的验证

ValidationResult result = Sheetz.validate("products.csv", Product.class);

System.out.println("Valid rows: "   + result.validCount());
System.out.println("Errors: "       + result.errorCount());
System.out.println("Success rate: " + result.successRate() + "%");

for (ValidationResult.RowError error : result.errors()) {
    System.out.println("Row "    + error.row() +
                       ", Col '" + error.column() +
                       "': "     + error.message());
}

// Clean rows only
List validProducts = result.validRows();

流畅构建器 – 完全控制

// Reader Builder
List products = Sheetz.reader(Product.class)
    .file("products.xlsx")
    .sheet("Inventory")      // By name
    .headerRow(1)            // Header on row 2 (0‑based)
    .delimiter(';')         // For semicolon‑delimited CSVs
    .read();

// Writer Builder
Sheetz.writer(Product.class)
    .data(products)
    .file("output.xlsx")
    .sheet("Products")
    .autoSize(true)          // Auto‑fit column widths
    .freezeHeader(true)      // Freeze the header row
    .write();

多工作表工作簿

Sheetz.workbook()
    .sheet("Products",  products)
    .sheet("Employees", employees)
    .sheet("Orders",    orders)
    .write("report.xlsx");

自定义转换器示例

public class MoneyConverter implements Converter {

    @Override
    public BigDecimal fromCell(Object value, ConvertContext ctx) {
        String str = value.toString()
                         .replace("$", "")
                         .replace(",", "")
                         .trim();
        return new BigDecimal(str);
    }

    @Override
    public Object toCell(BigDecimal value) {
        return "$" + value.setScale(2, RoundingMode.HALF_UP);
    }
}

通过注解对单个字段使用

@Column(converter = MoneyConverter.class)
public BigDecimal price;

或全局注册以用于所有 BigDecimal 字段

Sheetz.register(BigDecimal.class, new MoneyConverter());

Source:

支持的类型及示例值

类型示例值
String任意文本
Integer, Long, Double, Float42, 3.14
BigDecimal, BigInteger99.99, 999999999
Booleantrue, yes, y, 1, on (不区分大小写)
LocalDate, LocalDateTime2024-01-15, 2024-01-15 10:30:00
ZonedDateTime, Instant2024-01-15T10:30:00Z
UUID550e8400-e29b-41d4-a716-446655440000
EnumACTIVE, active (不区分大小写)

格式支持

格式读取写入流式
.xlsx (Excel 2007+)✅ SAX / SXSSF
.xls (Excel 97‑2003)
.csv✅ Buffered

全局配置

想要在整个应用中更改默认日期格式或 CSV 编码吗?创建一个单独的配置对象并全局应用:

SheetzConfig config = SheetzConfig.builder()
    .dateFormat("dd/MM/yyyy")
    .dateTimeFormat("dd/MM/yyyy HH:mm")
    .trimValues(true)
    .skipEmptyRows(true)
    .streamingThreshold(10_000)   // Auto‑stream above this row count
    .charset(StandardCharsets.ISO_8859_1)
    .build();

Sheetz.configure(config);

入门

git clone https://github.com/chitralabs/sheetz.git
cd sheetz
mvn clean install

要求

  • Java 11+
  • Apache POI 5.2.5
  • OpenCSV 5.9

许可证: Apache 2.0

基准测试与示例

  • 基准测试sheetz-benchmarks 仓库包含与 Apache POI、EasyExcel、FastExcel 和 Poiji 的并排 JMH 性能比较,提供完整源码,您可以自行运行。
  • 示例sheetz-examples 仓库提供 8 个可运行的演示,覆盖端到端的使用案例。

贡献

Sheetz 刚刚发布,正在积极寻找贡献者、问题和反馈。如果你曾经想要一种无需一周 POI 设置就能直接使用的 Excel/CSV 处理工具,试一试吧,如果觉得有用请点个 ⭐。

👉 GitHub: https://github.com/chitralabs/sheetz

讨论

你目前在 Java 中用于 Excel 或 CSV 处理的首选库是什么?请在评论中告诉我——我想了解社区是如何解决这个痛点的!

0 浏览
Back to Blog

相关文章

阅读更多 »