1. 简介
本文将带你快速掌握 Univocity Parsers —— 一个功能强大、性能优异的 Java 库,用于解析和生成 CSV、TSV 以及定长(fixed-width)格式的文本文件。
我们会从基础的文件读写操作讲起,逐步过渡到与 Java Bean 的绑定操作,最后介绍一些关键配置项。整个过程简洁高效,适合在实际项目中直接套用。
✅ 适合场景:大批量数据导入导出、ETL 工具开发、对接第三方系统文本接口等。
⚠️ 踩坑提示:别再用 OpenCSV 了,遇到复杂格式或性能要求高时,Univocity 真的是降维打击。
2. 项目依赖配置
要使用 Univocity Parsers,只需在 pom.xml
中引入以下 Maven 依赖:
<dependency>
<groupId>com.univocity</groupId>
<artifactId>univocity-parsers</artifactId>
<version>2.8.4</version>
</dependency>
这个库不依赖其他第三方包,轻量且稳定,可以直接上生产。
3. 基础用法
3.1. 文件读取
✅ CSV/TSV 读取(极简模式)
直接通过 CsvParser
或 TsvParser
将整个文件解析为 String[]
列表:
try (Reader inputReader = new InputStreamReader(
new FileInputStream(new File("src/test/resources/productList.csv")), "UTF-8")) {
CsvParser parser = new CsvParser(new CsvParserSettings());
List<String[]> parsedRows = parser.parseAll(inputReader);
return parsedRows;
} catch (IOException e) {
// 异常处理
}
📌 想读 TSV?把 CsvParser
换成 TsvParser
即可,其他代码完全不变。
✅ 定长文件读取(fixed-width)
定长文件的关键是提前定义每列的宽度。你需要通过 FixedWidthFields
明确指定字段长度:
try (Reader inputReader = new InputStreamReader(
new FileInputStream(new File("src/test/resources/productList.txt")), "UTF-8")) {
FixedWidthFields fieldLengths = new FixedWidthFields(8, 30, 10);
FixedWidthParserSettings settings = new FixedWidthParserSettings(fieldLengths);
FixedWidthParser parser = new FixedWidthParser(settings);
List<String[]> parsedRows = parser.parseAll(inputReader);
return parsedRows;
} catch (IOException e) {
// 异常处理
}
比如上面的例子表示三列:第一列 8 字符,第二列 30 字符,第三列 10 字符。
3.2. 文件写入
写操作和读操作对称,只需选择对应的 Writer
实现即可。
以下是一个通用方法,支持输出 CSV、TSV 和定长格式:
public boolean writeData(List<Object[]> products, OutputType outputType, String outputPath) {
try (Writer outputWriter = new OutputStreamWriter(
new FileOutputStream(new File(outputPath)), "UTF-8")) {
switch(outputType) {
case CSV:
CsvWriter writer = new CsvWriter(outputWriter, new CsvWriterSettings());
writer.writeRowsAndClose(products);
break;
case TSV:
TsvWriter writer = new TsvWriter(outputWriter, new TsvWriterSettings());
writer.writeRowsAndClose(products);
break;
case FIXED_WIDTH:
FixedWidthFields fieldLengths = new FixedWidthFields(8, 30, 10);
FixedWidthWriterSettings settings = new FixedWidthWriterSettings(fieldLengths);
FixedWidthWriter writer = new FixedWidthWriter(outputWriter, settings);
writer.writeRowsAndClose(products);
break;
default:
logger.warn("无效的输出类型: " + outputType);
return false;
}
return true;
} catch (IOException e) {
// 异常处理
}
return false;
}
📌 注意:定长写入必须提供字段宽度,否则会抛异常。
3.3. 使用行处理器(Row Processor)
当数据量较大时,你不希望一次性加载全部内容到内存。这时可以用 Row Processor 实现流式处理。
举个例子:使用 BatchedColumnProcessor
每次处理 5 行数据:
try (Reader inputReader = new InputStreamReader(
new FileInputStream(new File(relativePath)), "UTF-8")) {
CsvParserSettings settings = new CsvParserSettings();
settings.setProcessor(new BatchedColumnProcessor(5) {
@Override
public void batchProcessed(int rowsInThisBatch) {
// 每处理完一批就会触发
System.out.println("已处理 " + rowsInThisBatch + " 行");
}
});
CsvParser parser = new CsvParser(settings);
parser.parse(inputReader); // 不再返回 List,而是由 processor 处理
} catch (IOException e) {
// 异常处理
}
✅ 优势:内存友好,适合处理百万级数据。
⚠️ 注意:调用 parseAll()
会加载全部数据,而 parse()
配合 processor 才能实现流式处理。
3.4. 与 Java Bean 绑定读写
光处理字符串数组太原始了,实际开发中我们更希望直接映射到 POJO。
Univocity 支持通过注解自动绑定字段,简单粗暴。
✅ 定义带注解的 Bean
public class Product {
@Parsed(field = "product_no")
private String productNumber;
@Parsed
private String description;
@Parsed(field = "unit_price")
private float unitPrice;
// getter 和 setter 省略
}
📌 关键注解是 @Parsed
:
- 如果字段名和 CSV 列名一致,直接
@Parsed
即可; - 如果不一致,用
field
属性指定列名。
✅ 读取 CSV 到 Bean 列表
try (Reader inputReader = new InputStreamReader(
new FileInputStream(new File("src/test/resources/productList.csv")), "UTF-8")) {
BeanListProcessor<Product> rowProcessor = new BeanListProcessor<>(Product.class);
CsvParserSettings settings = new CsvParserSettings();
settings.setHeaderExtractionEnabled(true); // 自动提取首行为 header
settings.setProcessor(rowProcessor);
CsvParser parser = new CsvParser(settings);
parser.parse(inputReader);
return rowProcessor.getBeans(); // 获取转换后的 Product 列表
} catch (IOException e) {
// 异常处理
}
📌 核心是 BeanListProcessor
,它会在解析过程中自动将每行数据映射为 Product
对象。
✅ 将 Bean 写入定长文件
try (Writer outputWriter = new OutputStreamWriter(
new FileOutputStream(new File(outputPath)), "UTF-8")) {
BeanWriterProcessor<Product> rowProcessor = new BeanWriterProcessor<>(Product.class);
FixedWidthFields fieldLengths = new FixedWidthFields(8, 30, 10);
FixedWidthWriterSettings settings = new FixedWidthWriterSettings(fieldLengths);
settings.setHeaders("product_no", "description", "unit_price"); // 显式设置列头
settings.setRowWriterProcessor(rowProcessor);
FixedWidthWriter writer = new FixedWidthWriter(outputWriter, settings);
writer.writeHeaders(); // 先写列头
for (Product product : products) {
writer.processRecord(product); // 逐条写入
}
writer.close();
return true;
} catch (IOException e) {
// 异常处理
}
📌 注意:
- 必须设置
setRowWriterProcessor
; processRecord()
是逐条写入的核心方法;writeHeaders()
可选,但建议加上便于阅读。
4. 常用配置项(Settings)
Univocity 提供了丰富的配置选项,可以精细控制解析行为。
以下是一些常用配置示例:
CsvParserSettings settings = new CsvParserSettings();
// 限制单列最大字符数,防止 OOM
settings.setMaxCharsPerColumn(100);
// 限制最大列数,避免异常数据导致解析失败
settings.setMaxColumns(50);
// 启用自动检测列头(推荐开启)
settings.setHeaderExtractionEnabled(true);
// 设置跳过空行
settings.setEmptyValue(null);
// 设置引号、分隔符等(默认已适配大多数情况)
settings.getFormat().setDelimiter(';');
settings.getFormat().setQuote('"');
📌 小技巧:可以通过 settings.getFormat()
调整格式化细节,比如分隔符、换行符、引号等。
不同类型解析器的 settings 有共性也有差异:
CsvParserSettings
/CsvWriterSettings
TsvParserSettings
/TsvWriterSettings
FixedWidthParserSettings
/FixedWidthWriterSettings
但整体使用模式高度统一,学一个等于会三个。
5. 总结
Univocity Parsers 是处理结构化文本文件的终极利器,具备以下优势:
✅ 支持 CSV、TSV、定长三种主流格式
✅ 性能强劲,远超 OpenCSV、Jackson CSV 等方案
✅ 提供 Java Bean 映射、流式处理、批量控制等高级功能
✅ API 设计清晰,配置灵活,文档齐全
📌 推荐使用场景:
- 数据导入导出模块
- 批量任务(如定时同步)
- 接口对接(尤其银行、政府类系统常用定长格式)
最后,源码已托管在 GitHub:https://github.com/eugenp/tutorials/tree/master/libraries-data-2,建议集合备用。
🚀 下次遇到文本解析需求,别再手撸了,Univocity 直接安排上。