rustfs-erasure-codec 7.0.0

Rust implementation of Reed-Solomon erasure coding
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
# Rust 流式文件处理实战指南

> **文档版本**: 2026-05-31
> **适用 Rust 版本**: 1.70+
> **关键词**: 流式处理、文件 IO、BufRead、异步 IO、大文件处理

---

## 目录

1. [核心答案:Rust 完全支持流式处理]#一核心答案rust-完全支持流式处理
2. [同步流式处理(std::io)]#二同步流式处理stdio
3. [异步流式处理(tokio)]#三异步流式处理tokio
4. [流式处理大型文件的实战模式]#四流式处理大型文件的实战模式
5. [性能关键点]#五性能关键点
6. [异步生态中的流式处理]#六异步生态中的流式处理
7. [完整实战案例:流式日志分析器]#七完整实战案例流式日志分析器
8. [总结:何时用何种方式]#八总结何时用何种方式

---

## 一、核心答案:Rust 完全支持流式处理

Rust 通过 `std::io` trait 体系(`Read`/`Write`/`BufRead`)以及异步生态(`tokio::io::AsyncRead`/`AsyncWrite`)原生支持流式处理,无需将整个文件加载到内存。

**核心 trait 关系**:

```
std::io::Read          ─── 逐字节/逐块读取
std::io::BufRead       ─── 在 Read 基础上增加缓冲,支持逐行读取
std::io::Write         ─── 逐字节/逐块写入
std::io::BufWriter     ─── 在 Write 基础上增加缓冲,减少系统调用
std::io::copy          ─── 流式拷贝(内部 8KB 栈缓冲,零堆分配)
```

---

## 二、同步流式处理(std::io)

### 2.1 基础:逐块读取

```rust
use std::fs::File;
use std::io::{self, Read};

// 方法1:固定缓冲区逐块读取
fn process_in_chunks(path: &str, chunk_size: usize) -> io::Result<u64> {
    let mut file = File::open(path)?;
    let mut buffer = vec![0u8; chunk_size]; // 例如 8KB,而非整个文件
    let mut total_bytes = 0u64;

    loop {
        let bytes_read = file.read(&mut buffer)?;
        if bytes_read == 0 {
            break; // EOF
        }
        total_bytes += bytes_read as u64;
        // 处理 buffer[..bytes_read] —— 只处理实际读到的部分
        process_data(&buffer[..bytes_read]);
    }
    Ok(total_bytes)
}
```

### 2.2 BufRead:逐行流式处理(最常用)

```rust
use std::fs::File;
use std::io::{self, BufRead, BufReader};

fn stream_lines(path: &str) -> io::Result<()> {
    let file = File::open(path)?;
    let reader = BufReader::with_capacity(64 * 1024, file); // 64KB 缓冲区

    for line in reader.lines() {
        let line = line?;
        // 每次只有一行在内存中
        process_line(&line);
    }
    Ok(())
}

// 手动 BufRead(更灵活,避免 String 分配)
fn stream_lines_manual(path: &str) -> io::Result<()> {
    let file = File::open(path)?;
    let mut reader = BufReader::with_capacity(64 * 1024, file);
    let mut line = String::new();

    loop {
        line.clear();
        let bytes = reader.read_line(&mut line)?;
        if bytes == 0 {
            break;
        }
        // line 包含换行符,可 trim
        process_line(line.trim_end());
    }
    Ok(())
}
```

### 2.3 流式写入

```rust
use std::fs::File;
use std::io::{self, BufRead, BufReader, BufWriter, Write};

fn stream_write(input_path: &str, output_path: &str) -> io::Result<u64> {
    let mut reader = BufReader::new(File::open(input_path)?);
    let mut writer = BufWriter::new(File::create(output_path)?);
    let mut total = 0u64;

    loop {
        let buf = reader.fill_buf()?; // 零拷贝获取内部缓冲区
        if buf.is_empty() {
            break;
        }
        writer.write_all(buf)?;
        let consumed = buf.len();
        total += consumed as u64;
        reader.consume(consumed); // 标记已消费
    }
    writer.flush()?;
    Ok(total)
}

// 最简洁版本:std::io::copy 自动以 8KB 缓冲区流式传输
fn copy_stream(input: &str, output: &str) -> io::Result<u64> {
    let mut src = File::open(input)?;
    let mut dst = File::create(output)?;
    io::copy(&mut src, &mut dst) // 内部使用 8KB 栈缓冲区,零堆分配
}
```

### 2.4 自定义 Read 组合器(流式管道)

```rust
use std::fs::File;
use std::io::{self, BufReader, BufWriter, Read, Write};

// Read 组合器可以链式组合,形成流式管道
fn stream_with_transform(input: &str, output: &str) -> io::Result<u64> {
    let file = File::open(input)?;
    let mut reader = BufReader::new(file);

    // 链式组合:Take → 转换 → 写入
    let limited = (&mut reader).take(1024 * 1024); // 只读前 1MB
    let mut writer = BufWriter::new(File::create(output)?);

    // 流式管道:数据按缓冲区大小流过,不会全部加载
    io::copy(&mut limited.take(1024 * 1024), &mut writer)
}

// 自定义 Read 适配器:流式大写转换
struct UpperReader<R: Read> {
    inner: R,
}

impl<R: Read> Read for UpperReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let n = self.inner.read(buf)?;
        for byte in &mut buf[..n] {
            if byte.is_ascii_lowercase() {
                byte.make_ascii_uppercase();
            }
        }
        Ok(n)
    }
}

fn stream_uppercase(input: &str, output: &str) -> io::Result<u64> {
    let reader = UpperReader { inner: File::open(input)? };
    let mut writer = BufWriter::new(File::create(output)?);
    io::copy(&mut BufReader::new(reader), &mut writer)
}
```

---

## 三、异步流式处理(tokio)

### 3.1 异步逐块读写

```rust
use tokio::fs::File;
use tokio::io::{self, AsyncReadExt, AsyncWriteExt};

async fn async_stream_copy(input: &str, output: &str) -> io::Result<u64> {
    let mut reader = File::open(input).await?;
    let mut writer = File::create(output).await?;
    let mut buffer = vec![0u8; 8192];
    let mut total = 0u64;

    loop {
        let n = reader.read(&mut buffer).await?;
        if n == 0 {
            break;
        }
        writer.write_all(&buffer[..n]).await?;
        total += n as u64;
    }
    writer.flush().await?;
    Ok(total)
}

// 最简洁:tokio::io::copy
async fn async_copy(input: &str, output: &str) -> io::Result<u64> {
    let mut src = File::open(input).await?;
    let mut dst = File::create(output).await?;
    io::copy(&mut src, &mut dst).await
}
```

### 3.2 异步逐行流式处理

```rust
use tokio::fs::File;
use tokio::io::{AsyncBufReadExt, BufReader};

async fn async_stream_lines(path: &str) -> std::io::Result<()> {
    let file = File::open(path).await?;
    let reader = BufReader::with_capacity(64 * 1024, file);
    let mut lines = reader.lines();

    while let Some(line) = lines.next_line().await? {
        process_line_async(&line).await;
    }
    Ok(())
}
```

### 3.3 异步流式管道(tokio::io::copy + 转换)

```rust
use tokio::io::AsyncRead;
use std::io;
use std::task::{Context, Poll};
use std::pin::Pin;

// 自定义异步 Read 适配器
struct AsyncUpperReader<R: AsyncRead + Unpin> {
    inner: R,
}

impl<R: AsyncRead + Unpin> AsyncRead for AsyncUpperReader<R> {
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut tokio::io::ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        let this = self.get_mut();
        let before = buf.filled().len();
        Pin::new(&mut this.inner).poll_read(cx, buf)?;
        // 转换本次读到的字节
        for byte in &mut buf.filled_mut()[before..] {
            byte.make_ascii_uppercase();
        }
        Poll::Ready(Ok(()))
    }
}
```

---

## 四、流式处理大型文件的实战模式

### 4.1 模式一:流式 CSV 处理(csv crate)

```rust
use csv;
use std::fs::File;
use std::io::BufReader;

fn stream_csv(path: &str) -> csv::Result<()> {
    let file = File::open(path)?;
    let reader = BufReader::with_capacity(128 * 1024, file);
    let mut rdr = csv::ReaderBuilder::new()
        .has_headers(true)
        .from_reader(reader); // 流式,不加载全部

    for result in rdr.records() {
        let record = result?;
        // 每次只有一行记录在内存
        println!("{:?}", record);
    }
    Ok(())
}

// 流式 CSV 转换 + 写入
fn transform_csv(input: &str, output: &str) -> csv::Result<()> {
    let file_in = BufReader::new(File::open(input)?);
    let mut rdr = csv::Reader::from_reader(file_in);

    let file_out = File::create(output)?;
    let mut wtr = csv::Writer::from_writer(BufWriter::new(file_out));

    for result in rdr.records() {
        let record = result?;
        // 转换后流式写出
        wtr.write_record(&record)?;
    }
    wtr.flush()?;
    Ok(())
}
```

### 4.2 模式二:流式 JSON 处理(serde_json::StreamDeserializer)

```rust
use serde::Deserialize;
use serde_json;
use std::fs::File;
use std::io::BufReader;

#[derive(Deserialize, Debug)]
struct Record {
    id: u64,
    name: String,
}

// 流式读取 JSON Lines(.jsonl)格式
fn stream_jsonl(path: &str) -> serde_json::Result<()> {
    let file = File::open(path)?;
    let reader = BufReader::with_capacity(64 * 1024, file);

    let stream = serde_json::Deserializer::from_reader(reader)
        .into_iter::<Record>();

    for result in stream {
        let record = result?;
        // 每次只反序列化一个对象
        println!("{:?}", record);
    }
    Ok(())
}
```

### 4.3 模式三:流式压缩/解压(flate2 crate)

```rust
use flate2::read::{GzDecoder, GzEncoder};
use flate2::Compression;
use std::fs::File;
use std::io::{self, BufRead, BufReader, BufWriter, Read, Write};

// 流式 Gzip 压缩:数据按块流过压缩器
fn stream_compress(input: &str, output: &str) -> io::Result<()> {
    let reader = BufReader::new(File::open(input)?);
    let encoder = GzEncoder::new(reader, Compression::default());
    let mut writer = BufWriter::new(File::create(output)?);
    // 数据不会全部加载到内存
    io::copy(&mut BufReader::new(encoder), &mut writer)?;
    Ok(())
}

// 流式 Gzip 解压 + 逐行处理
fn stream_decompress_lines(path: &str) -> io::Result<()> {
    let file = File::open(path)?;
    let decoder = GzDecoder::new(BufReader::new(file));
    let reader = BufReader::new(decoder);

    for line in reader.lines() {
        let line = line?;
        process_line(&line);
    }
    Ok(())
}
```

### 4.4 模式四:流式搜索(grep 逻辑)

```rust
use std::fs::File;
use std::io::{self, BufRead, BufReader, Write, BufWriter};

fn stream_grep(path: &str, pattern: &str) -> io::Result<()> {
    let file = File::open(path)?;
    let reader = BufReader::with_capacity(64 * 1024, file);
    let stdout = io::stdout();
    let mut out = BufWriter::new(stdout.lock());

    for (i, line) in reader.lines().enumerate() {
        let line = line?;
        if line.contains(pattern) {
            writeln!(out, "{}:{}", i + 1, line)?;
        }
    }
    out.flush()?;
    Ok(())
}
```

### 4.5 模式五:流式哈希计算

```rust
use sha2::{Sha256, Digest};
use std::fs::File;
use std::io::{self, BufReader, Read};

fn stream_hash(path: &str) -> io::Result<String> {
    let file = File::open(path)?;
    let mut reader = BufReader::with_capacity(64 * 1024, file);
    let mut hasher = Sha256::new();
    let mut buffer = [0u8; 8192];

    loop {
        let n = reader.read(&mut buffer)?;
        if n == 0 {
            break;
        }
        hasher.update(&buffer[..n]);
    }
    Ok(format!("{:x}", hasher.finalize()))
}
```

---

## 五、性能关键点

| 要点 | 说明 |
|------|------|
| **缓冲区大小** | 默认 8KB,SSD 上 64KB-128KB 最优,HDD 上 256KB+ |
| **BufReader/Writer** | 减少系统调用次数,必须使用 |
| **io::copy** | 内部 8KB 栈缓冲,零堆分配,适合纯拷贝 |
| **fill_buf + consume** | 零拷贝读取,避免额外复制 |
| **内存映射 vs 流式** | 随机访问用 mmap,顺序处理用流式 |
| **并行流式** | 用 rayon 并行处理已读取的块 |

### 5.1 并行流式处理(rayon)

```rust
use rayon::prelude::*;
use std::fs::File;
use std::io::{BufRead, BufReader};

fn parallel_stream(path: &str) -> std::io::Result<()> {
    let file = File::open(path)?;
    let reader = BufReader::new(file);

    // 收集到 Vec 以支持并行(需要折中:行数远小于文件大小时可行)
    // 对于超大文件,使用 chunk-based 并行更好
    let lines: Vec<String> = reader.lines().collect::<std::io::Result<_>>()?;

    lines.par_iter().for_each(|line| {
        process_line_expensive(line);
    });

    Ok(())
}

// 真正的流式并行:按块并行处理
use std::io::{Read, Seek, SeekFrom};

fn parallel_chunk_stream(path: &str, num_threads: usize) -> std::io::Result<()> {
    use std::sync::Arc;
    use std::thread;

    let file_size = std::fs::metadata(path)?.len();
    let chunk_size = file_size / num_threads as u64;

    let path = Arc::new(path.to_string());
    let handles: Vec<_> = (0..num_threads).map(|i| {
        let path = Arc::clone(&path);
        let start = i as u64 * chunk_size;
        let end = if i == num_threads - 1 { file_size } else { start + chunk_size };

        thread::spawn(move || -> std::io::Result<()> {
            let mut file = File::open(path.as_ref())?;
            file.seek(SeekFrom::Start(start))?;
            let mut reader = BufReader::new(file).take(end - start);

            // 每个线程流式处理自己的分片
            let mut line = String::new();
            loop {
                line.clear();
                let n = reader.read_line(&mut line)?;
                if n == 0 { break; }
                process_line(&line);
            }
            Ok(())
        })
    }).collect();

    for h in handles {
        h.join().unwrap()?;
    }
    Ok(())
}
```

---

## 六、异步生态中的流式处理

### 6.1 tokio + tokio-util 管道

```rust
use tokio::fs::File;
use tokio::io::{AsyncBufReadExt, BufReader};

// tokio stream 适配(需要 async-stream crate)
async fn async_line_stream(path: &str) -> impl futures::Stream<Item = String> {
    let file = File::open(path).await.unwrap();
    let reader = BufReader::new(file);

    async_stream::stream! {
        let mut lines = reader.lines();
        while let Ok(Some(line)) = lines.next_line().await {
            yield line;
        }
    }
}
```

### 6.2 异步流式 HTTP 响应(actix-web 示例)

```rust
use actix_web::{HttpResponse};
use tokio::fs::File;

async fn stream_file() -> HttpResponse {
    let file = File::open("large_file.csv").await.unwrap();

    // 以流式 body 返回,内存占用恒定
    HttpResponse::Ok()
        .content_type("application/octet-stream")
        .streaming(tokio_util::io::ReaderStream::new(file))
}
```

---

## 七、完整实战案例:流式日志分析器

```rust
use std::collections::HashMap;
use std::fs::File;
use std::io::{self, BufRead, BufReader, Write, BufWriter};

struct LogStats {
    total_lines: u64,
    error_count: u64,
    warn_count: u64,
    status_codes: HashMap<u16, u64>,
}

impl LogStats {
    fn new() -> Self {
        Self {
            total_lines: 0,
            error_count: 0,
            warn_count: 0,
            status_codes: HashMap::new(),
        }
    }

    // 流式处理:内存恒定,无论文件多大
    fn analyze(&mut self, path: &str) -> io::Result<()> {
        let file = File::open(path)?;
        let reader = BufReader::with_capacity(256 * 1024, file); // 256KB 缓冲

        for line in reader.lines() {
            let line = line?;
            self.total_lines += 1;

            if line.contains("ERROR") {
                self.error_count += 1;
            } else if line.contains("WARN") {
                self.warn_count += 1;
            }

            // 提取 HTTP 状态码(简化示例)
            if let Some(code) = extract_status_code(&line) {
                *self.status_codes.entry(code).or_insert(0) += 1;
            }
        }
        Ok(())
    }

    fn report(&self, output: &str) -> io::Result<()> {
        let mut w = BufWriter::new(File::create(output)?);
        writeln!(w, "Total lines: {}", self.total_lines)?;
        writeln!(w, "Errors: {}", self.error_count)?;
        writeln!(w, "Warnings: {}", self.warn_count)?;
        for (code, count) in &self.status_codes {
            writeln!(w, "HTTP {}: {}", code, count)?;
        }
        w.flush()
    }
}

fn extract_status_code(line: &str) -> Option<u16> {
    // 简化:查找 " HTTP/1.1\" 200 " 模式
    line.find(" HTTP/").and_then(|i| {
        line[i+1..].find(' ').and_then(|j| {
            line[i+1+j+1..].find(' ').and_then(|k| {
                line[i+1+j+1..i+1+j+1+k].parse().ok()
            })
        })
    })
}
```

---

## 八、总结:何时用何种方式

| 场景 | 方案 | 内存占用 |
|------|------|----------|
| 逐行处理文本 | `BufReader::lines()` | 恒定(~1行 + 缓冲区) |
| 逐块二进制复制 | `io::copy` / `read` 循环 | 恒定(8KB) |
| 流式压缩/解压 | `flate2` + `BufReader` 包装 | 恒定 |
| 流式 CSV/JSON | `csv` / `serde_json` stream | 恒定 |
| 大文件哈希 | `Read` 循环 + `Digest::update` | 恒定 |
| 随机访问大文件 | `mmap`(memmap2 crate) | 按需分页 |
| 异步高并发 IO | `tokio::io` + `BufReader` | 恒定 |
| HTTP 流式响应 | `tokio_util::io::ReaderStream` | 恒定 |

---

## 附录:常用 Cargo 依赖

```toml
[dependencies]
# 异步运行时
tokio = { version = "1", features = ["fs", "io-util", "io-std"] }
tokio-util = { version = "0.7", features = ["io"] }
futures = "0.3"
async-stream = "0.3"

# 流式压缩
flate2 = "1"

# 流式 CSV
csv = "1"

# 流式 JSON
serde = { version = "1", features = ["derive"] }
serde_json = "1"

# 流式哈希
sha2 = "0.10"

# 并行处理
rayon = "1"

# 内存映射(随机访问场景)
memmap2 = "0.9"
```

---

> **核心结论**: Rust 的 `Read`/`Write` trait 体系天然就是流式设计——数据按缓冲区大小流过管道,内存占用恒定,与文件大小无关。这是 Rust 处理大文件的核心优势。