Apache POI와 씨름을 그만—Java용 한 줄 Excel 라이브러리 Sheetz

발행: (2026년 2월 18일 오후 02:18 GMT+9)
8 분 소요
원문: Dev.to

Source: Dev.to

If you’ve ever processed an Excel file in Java, you know the drill:

  • Apache POI를 가져옵니다.
  • 컬럼 헤더를 읽기 위해 수십 줄의 보일러플레이트 코드를 작성합니다.
  • 누군가 셀을 비워두어 행 14에서 NullPointerException을 디버깅하는 데 한 시간을 소비합니다.

Sound familiar?

Sheetz is an open‑source Java library that collapses all of that pain into a single line of code:

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

No boiler‑plate. No ceremony. Just data.

왜 Sheetz인가?

Apache POI는 강력하지만, 개발자 편의성을 위해 설계된 것은 아닙니다.
EasyExcel, FastExcel, Poiji가 더 나은 편이지만, 여전히 꽤 많은 설정이 필요합니다.

Sheetz는 다른 철학을 취합니다: 기본적으로 설정이 전혀 없고, 필요할 때는 완전한 제어.

기본 제공 기능

Feature
🚀원‑라인 API – Sheetz.read(), Sheetz.write(), 끝
📊진정한 SAX 스트리밍 – 백만 행 파일을 약 10 MB 메모리로 일정하게 처리
🔄자동 타입 변환 – 19개의 내장 변환기(날짜, 열거형, BigDecimal, UUID, …)
🧵스레드‑안전 – 동시 사용에 안전
내장 검증 – 행/열 컨텍스트와 함께 상세 오류 보고
📝어노테이션 매핑 – 사용자 정의 헤더, 필수 필드, 기본값 등을 위한 @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 수준으로 유지됩니다.

// 행별로 처리 – 상수 메모리
Sheetz.stream("huge-file.xlsx", Product.class)
      .forEach(product -> process(product));

// 배치 처리 – 대량 DB 삽입에 최적
Sheetz.stream("huge-file.xlsx", Product.class)
      .batch(1000)
      .forEach(batch -> database.bulkInsert(batch));

// 전체 Java Streams 지원
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();

Fluent Builder – 전체 제어

// 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");

Custom Converter Example

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());

지원되는 유형 및 예시 값

유형예시 값
StringAny text
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개의 실행 가능한 데모를 제공합니다.

Contribute

Sheetz는 막 출시된 상태이며, 적극적으로 기여자, 이슈, 피드백을 찾고 있습니다. POI 설정에 일주일을 들이지 않고 바로 작동하는 Excel/CSV 처리를 원하셨다면, 한번 사용해 보시고 유용하다고 생각되면 ⭐를 남겨 주세요.

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

Discussion

현재 Java에서 Excel 또는 CSV 처리를 위해 주로 사용하는 라이브러리는 무엇인가요? 댓글에 알려 주세요—커뮤니티가 이 문제를 어떻게 해결하고 있는지 궁금합니다!

0 조회
Back to Blog

관련 글

더 보기 »

GStreamer

오늘의 주제: 도구를 제공하여 미디어 스트림을 강력한 새로운 방식으로 조작하고 처리함으로써 보다 정교한 멀티미디어 애플리케이션을 구축하도록 지원합니다.