12 个稳定版本
2.2.1 | 2022 年 3 月 30 日 |
---|---|
2.2.0 | 2022 年 3 月 29 日 |
2.1.0 | 2021 年 3 月 27 日 |
1.4.0 | 2020 年 12 月 31 日 |
0.1.0 | 2020 年 6 月 30 日 |
#897 in 文本处理
41 每月下载量
155KB
4K SLoC
CSVSC
用于在 csv 文件上构建转换链的库。
文档
lib.rs
:
csvsc
是一个构建 csv 文件处理器的框架。
想象一下,你有 N 个具有相同结构的 csv 文件,你想要使用它们来创建 M 个新的 csv 文件,这些文件的信息以某种方式依赖于原始文件。csvcv 就是为了这个目的而构建的。使用这个工具,你可以构建一个处理链(行流),它将逐个读取输入文件,并生成带有修改的新输出文件。
快速入门
使用 cargo 开始一个新的二进制项目
$ cargo new --bin miprocesadordecsv
在 Cargo.toml
中将 csvsc
和 encoding
添加为依赖项。
[dependencies]
csvsc = "2.2"
现在开始构建你的处理链。指定输入(一个或多个 csv 文件)、转换和输出。
use csvsc::prelude::*;
let mut chain = InputStreamBuilder::from_paths(&[
// Put here the path to your source files, from 1 to a million
"test/assets/chicken_north.csv",
"test/assets/chicken_south.csv",
]).unwrap().build().unwrap()
// Here is where you do the magic: add columns, remove ones, filter
// the rows, group and aggregate, even probably transpose the data
// to fit your needs.
// Specify some (zero, one or many) output targets so that results of
// your computations get stored somewhere.
.flush(Target::path("data/output.csv")).unwrap()
.into_iter();
// And finally consume the stream, reporting any errors to stderr.
while let Some(item) = chain.next() {
if let Err(e) = item {
eprintln!("{}", e);
}
}
示例
获取你的输入文件,在这种情况下,我将使用这两个
chicken_north.csv
month,eggs per week
1,3
1,NaN
1,6
2,
2,4
2,8
3,5
3,1
3,8
chicken_south.csv
month,eggs per week
1,2
1,NaN
1,
2,7
2,8
2,23
3,3
3,2
3,12
现在构建你的处理链。
// main.rs
use csvsc::prelude::*;
use encoding::all::UTF_8;
let mut chain = InputStreamBuilder::from_paths(vec![
"test/assets/chicken_north.csv",
"test/assets/chicken_south.csv",
]).unwrap()
// optionally specify the encoding
.with_encoding(UTF_8)
// optionally add a column with the path of the source file as specified
// in the builder
.with_source_col("_source")
// build the row stream
.build().unwrap()
// Filter some columns with invalid values
.filter_col("eggs per week", |value| {
value.len() > 0 && value != "NaN"
}).unwrap()
// add a column with a value obtained from the filename ¡wow!
.add(
Column::with_name("region")
.from_column("_source")
.with_regex("_([a-z]+).csv").unwrap()
.definition("$1")
).unwrap()
// group by two columns, compute some aggregates
.group(["region", "month"], |row_stream| {
row_stream.reduce(vec![
Reducer::with_name("region").of_column("region").last("").unwrap(),
Reducer::with_name("month").of_column("month").last("").unwrap(),
Reducer::with_name("avg").of_column("eggs per week").average().unwrap(),
Reducer::with_name("sum").of_column("eggs per week").sum(0.0).unwrap(),
]).unwrap()
})
// Write a report to a single file that will contain all the data
.flush(
Target::path("data/report.csv")
).unwrap()
// This column will allow us to output to multiple files, in this case
// a report by month
.add(
Column::with_name("monthly report")
.from_all_previous()
.definition("data/monthly/{month}.csv")
).unwrap()
.del(vec!["month"])
// Write every row to a file specified by its `monthly report` column added
// previously
.flush(
Target::from_column("monthly report")
).unwrap()
// Pack the processing chain into an interator that can be consumed.
.into_iter();
// Consuming the iterator actually triggers all the transformations.
while let Some(item) = chain.next() {
item.unwrap();
}
这是输出结果
data/monthly/1.csv
region,avg,sum
south,2,2
north,4.5,9
data/monthly/2.csv
region,avg,sum
north,6,12
south,12.666666666666666,38
data/monthly/3.csv
region,avg,sum
north,4.666666666666667,14
south,5.666666666666667,17
data/report.csv
region,month,avg,sum
north,2,6,12
south,1,2,2
south,2,12.666666666666666,38
north,3,4.666666666666667,14
south,3,5.666666666666667,17
north,1,4.5,9
深入了解
查看 InputStreamBuilder
了解启动处理链和读取输入的更多选项。
前往 RowStream
文档以查看所有可用的转换以及将数据刷新到文件或标准 I/O 的选项。
依赖项
~7MB
~105K SLoC