# Streaming Export Safety

当代码涉及 Excel/CSV/JSON/PDF 大文件导出、批量序列化、内存里构建大对象时触发。防止 OOM、临时文件残留、同步导出阻塞 HTTP 线程等内存安全陷阱。

- Repository: https://github.com/doccker/cc-use-exp (1063 stars)
- Category: Documents
- License: see repository
- Last updated: 2026-08-26
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add doccker/cc-use-exp --skill streaming-export-safety -g -a claude-code -y`
Codex: `npx skills add doccker/cc-use-exp --skill streaming-export-safety -g -a codex -y`
Cursor: `npx skills add doccker/cc-use-exp --skill streaming-export-safety -g -a cursor -y`
Gemini CLI: `npx skills add doccker/cc-use-exp --skill streaming-export-safety -g -a gemini-cli -y`
Claude Code plugin marketplace: `/plugin marketplace add doccker/cc-use-exp`

## Description

当代码涉及 Excel/CSV/JSON/PDF 大文件导出、批量序列化、内存里构建大对象时触发。防止 OOM、临时文件残留、同步导出阻塞 HTTP 线程等内存安全陷阱。

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# 流式导出 / 大对象内存安全

> 当一次性 in-memory 构建数据超过 1 万行 / 10 MB 时，必须切换为流式 API。
> 否则常见后果：**OOM**、Full GC 风暴、临时文件残留、HTTP 超时。

---

## 决策：什么时候必须流式？

| 数据量级 | 推荐模式 | 备注 |
|---------|---------|------|
| ≤ 1 万行 / ≤ 5 MB | 内存构建 OK | XSSFWorkbook / pandas / 普通 JSON 序列化 |
| 1 万 ~ 10 万行 | **强烈建议**流式 | 单机够用，但有 OOM 风险 |
| > 10 万行 / > 50 MB | **必须**流式 + 异步 | 内存模型会爆 |
| 数据量未知（用户驱动） | **必须**流式 + 上限保护 | 永远按最坏情况设计 |

**核心判断**：能不能预估上限？预估超过 1 万行就上流式。

---

## 陷阱 #1：Excel 大数据 → XSSFWorkbook 全量加载 OOM

### 嗅探信号

代码评审看到以下模式立即怀疑：

- `new XSSFWorkbook()` + 循环 `createRow` 超过 1 万次
- `EasyExcel.write(...).sheet().doWrite(data)` 中 `data.size() > 10000`
- `openpyxl.Workbook()`（未带 `write_only=True`）+ 循环 `append`
- `excelize.NewFile()` + `SetCellValue` 大量循环
- `ExcelJS.Workbook()`（未用 `stream` 子模块）

### 正确做法：Java + Apache POI SXSSF

```java
// ❌ XSSF 全量内存（10w 行直接 OOM）
XSSFWorkbook wb = new XSSFWorkbook();
Sheet sheet = wb.createSheet();
for (int i = 0; i < 100_000; i++) {
    Row row = sheet.createRow(i);
    row.createCell(0).setCellValue("data");
}

// ✅ SXSSF 流式（windowSize=100，超出窗口写临时文件）
SXSSFWorkbook wb = null;
try {
    wb = new SXSSFWorkbook(100);
    wb.setCompressTempFiles(true);
    Sheet sheet = wb.createSheet();
    for (int i = 0; i < 100_000; i++) {
        Row row = sheet.createRow(i);
        row.createCell(0).setCellValue("data");
    }
    try (OutputStream os = new FileOutputStream("out.xlsx")) {
        wb.write(os);
    }
} finally {
    if (wb != null) {
        wb.dispose();
    }
}
```

### SXSSF 限制（**必须**告知调用方）

- ❌ 不能随机访问已 flush 的行（超过 windowSize 后该行不可读）
- ❌ 不支持公式自动计算（需要预先 `evaluator.evaluateAll()`）
- ❌ 不支持 `cloneSheet`、不支持合并多个已写出的 Sheet
- ⚠️ 临时文件默认在 `java.io.tmpdir`，容器环境注意磁盘配额
- ⚠️ 必须 `dispose()`，否则临时文件残留

### EasyExcel（阿里）流式写入

The rest: https://github.com/doccker/cc-use-exp/blob/HEAD/.antigravity/skills/streaming-export-safety/SKILL.md
