-
Notifications
You must be signed in to change notification settings - Fork 0
/
第 12.00.03、io 包
708 lines (425 loc) · 18.6 KB
/
第 12.00.03、io 包
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
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
总览
io 包提供了 I/O 原语的基础界面
它主要的工作是包裹已经存在的原语的实现,
比如在 os 包中的内容,
并将它们转化为函数抽象后的公共通用的界面,再加上一些其他相关的原语
由于这些界面和原语用多种实现包裹了底层操作,
除非有其他声明,客户端不应假设它们是并行安全的
常量
查找位置
const (
SeekStart = 0 // 相对文件头查找
SeekCurrent = 1 // 相对当前位置查找
SeelEnd = 2 // 相对结尾处查找
)
变量
EOF 是当没有更多的输入可用时, Read 返回的错误
函数应仅在表示优雅的输入结束时才返回 EOF
若在一个结构数据流中,遇见了不可预计的 EOF,
恰当的错误应该是 ErrUnexpectEOF 或者其他一些能给出更详细细节的错误
var EOF = errors.New("EOF")
ErrClosedPipe 错误用于在一个关闭的管道上读或写时产生
var ErrClosedPipe = errors.New("io: read/write on closed pipe")
ErrNoProgress 被一个 io.Reader 的客户端返回,
当很多次 Read 调用都失败地返回任何数据或错误,
这通常预示着图个损坏的 io.Reader 实现
var ErrNoProgress = errors.New("multiple Read calls return no data or error")
ErrShortBuffer 意味着读取需要一个比当前所提供还要长的 buffer
var ErrShortBuffer = errors.New("short buffer")
ErrShortWrite 意味着写入接受的字节比需求的要短,但无法返回一个明确的错误
var ErrShortWrite = errors.New("short write")
ErrUnexpectedEOF 意味着在读取固定长度的块或数据结构的中间,遇到了 EOF
var ErrUnexpectedEOF = errors.New("unexpected EOF")
Copy(dst Writer, src Reader) (written int64, err error)
从 src 向 dst 拷贝,直到遇见 src 的 EOF 或者出现了一个错误
它返回已经拷贝的字节数,以及拷贝时遇到的第一个错误,若有的话
一个成功的拷贝应该返回 err == nil,而非 err == EOF
由于本函数被定义为从 src 读取直到 EOF,所以本函数不应该将 Read 读取的 EOF 当做错误对待
若 src 实现了 WriterTo 接口,则拷贝的实现是通过调用 src.WriteTo(dst)
其他情况下,若 dst 实现了 ReaderFrom,拷贝的实现则是通过调用 dst.ReadFrom(src)
EG.
r := strings.NewReader("some io.Reader stream to be read\n")
if _, err := io.Copy(os.Stdout, r); err != nil {
log.Fatal(err)
}
CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error)
本函数与 Copy 函数等同,除了本函数使用提供的缓存(若需要的话),而非零时划分出的缓存
若 buf 为 nil,则划分出一个来;其他情况下,若 buf 的长度为 0,本函数产生 panic
EG.
r1 := strings.NewReader("first reader\n")
r2 := strings.NewReader("second reader\n")
buf := make([]byte, 8)
// buf 在此使用...
if _, err := io.CopyBuffer(os.Stdout, r1, buf); err != nil {
log.Fatal(err)
}
// ... 在此复用,无需另外划分一个新的
if _, err := io.CopyBuffer(os.Stdout, r2, buf); err != nil {
log.Fatal(err)
}
CopyN(dst Writer, src Reader, n int64) (written int64, err error)
从 src 拷贝 n 字节(或直到遇到错误)至 dst
它返回拷贝的字节的数量,以及拷贝过程中最早遇到的错误
返回时,当且仅当 err == nil 时, written == n
EG.
r := strings.NewReader("some io.Reader stream to be read")
if _, err := io.CopyN(os.Stdout, r, 5); err != nil {
log.Fatal(err)
}
ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)
从 r 读取至 buf 中,直到读取到了至少 min 个字节数
返回拷贝的字节数,若少于指定的字节,则返回一个错误
仅在没有读取到任何字节的时候返回错误 EOF
若读取的字节数少于 min 指定的字节数,则返回 ErrUnexpectedEOF
若 min 比 buf 长度要大,则返回错误 ErrShortBuffer
当且仅当 err == nil 时,返回的 n >= min
EG.
r := strings.NewReader("some io.Reader stream to be read\n")
buf := make([]byte, 33)
if _, err := io.ReadAtLeast(r, buf, 4); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", buf)
// buffer 比 min 指定的要少
shortBuf := make([]byte, 3)
if _, err := io.ReadAtLeast(r, shortBuf, 4); err != nil {
fmt.Println("error:", err)
}
// 最小读取字节数比 io.Reader 流的要大
longBuf := make([]byte, 64)
if _, err := io.ReadAtLeast(r, longBuf, 64); err != nil {
fmt.Println("error:", err)
}
ReadFull(r Reader, buf []byte) (n int, err error)
从 r 准确读取 len(buf) 个字节至 buf 中
返回已拷贝的字节数,若拷贝的字节数少于原本的,则返回一个错误
仅当没有任何字节可读取时,才返回 EOF
若开始读取,但所读取的字节数少于指定的,本函数返回 ErrUnexpectedEOF
当且仅当 err == nil 时, n == len(buf)
EG.
r := strings.NewReader("some io.Reader stream to be read\n")
buf := make([]byte, 4)
if _, err := io.ReadFull(r, buf); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", buf)
// 最小读取字节数大于 io.Reader 流
longBuf := make([]byte, 64)
if _, err := io.ReadFull(r, longBuf); err != nil {
fmt.Println("error:", err)
}
WriteString(w Writer, s string) (n int, err error)
将字符串的内容写入 w 中,w 接受的是 []byte
若 w 实现了 WriteString 方法,则直接调用
其他情况下, w.Write 仅会调用一次
EG.
io.WriteString(os.Stdout, "Hello World")
ByteReader interface 类型
ByteReader 接口包裹了 ReadByte 方法
ReadByte 从输入中读取并返回下字节,或者任何遇到的错误
若 ReadByte 返回一个错误,则不会消耗输入的字节,返回的字节值将为未定义
type ByteReader interface {
ReadByte() (byte, error)
}
ByteScanner interface 类型
ByteScanner 接口为 将 UnreadByte 方法加入基础的 ReadByte 方法的接口
UnreadByte 导致下一次调用 ReadByte 时,返回和上一次调用 ReadByte 时返回相同的值
若在两次调用 UnreadByte 之间没有调用一次 ReadByte 时会是一个错误
type ByteScanner interface {
ByteReader
UnreadByte() error
}
ByteWriter interface 类型
ByteWriter 接口包裹了 WriteByte 方法
type ByteWriter interface {
WriteByte(c byte) error
}
Closer interface 类型
Closer 接口包裹了 Close 方法
在第一次调用 Close 方法之后再次调用 Close 方法是未定义的
若有特殊的实现,则应该为它们的行为写文档
type Closer interface {
Close() error
}
LimitedReader struct 类型
一个 LimitedReader 从 R 读取数据,但将返回的数据量限制为 N 字节
每次调用 Read 都会更新 N 来显示新剩余的总量
Read 返回 EOF,当 N <= 0,或者底层的 R 返回了 EOF
type LimitedReader struct {
R Reader // 底层的 reader
N int // 最大的剩余字节
}
(l *LimitedReader) Read(p []byte) (n int, err error)
PipeReader struct 类型
PipeReader 是一个管道的读取端
type PipeReader struct {
// 包含过滤的或未导出的字段
}
Pipe() (*PipeReader, *PipeWriter)
创建一个同步的内存中管道
它可以用来连接一个需要 io.Reader 的代码和一个需要 io.Writer 的代码
在管道上 Read 方法和 Write 方法是一一对应的,一个特例是,多个 Read 需要消耗一个 Write 的内容
也就说,每个次调用 Write 写入 PipeWriter 阻塞,直到它满足了 PipeReader 中一个或多个 Read 能完全消耗写入的数据
数据将直接从 Write 拷贝至对应的 Read 中;并不会有内部的 buffer
并行调用 Read 和 Write 或者 Close 都是安全的
并行调用多个 Read,以及并行调用多个 Write 也是安全的:
每个独立的调用都会按顺序过关
(r *PipeReader) Close() error
关闭 reader
其后向写入端的写入操作,都会返回错误 ErrClosedPipe
(r *PipeReader) CloseWithError(err error) error
关闭 reader
其后向写入端写入的操作,都会返回错误 err
(r *PipeReader) Read(date []byte) (n int, err error)
本方法实现了标准 Read 接口:
它从管道中读取数据,阻塞直到 writer 到达,或者写入端被关闭
若写入端 is closed with an error,那么那个 error 就会作为 err 返回,其他情况下 err 为 EOF
PipeWriter struct 类型
PipeWriter 为管道的写入端
PipeWriter struct {
// 包含过滤的或者未导出的字段
}
(w *PipeWriter) Close() error
关闭一个 writer
其后从读取端读取的操作,都不会返回字节,且返回 EOF
(w *PipeWriter) CloseWithError(err error) error
关闭一个 writer
其后从读取端的读取操作,都不会返回字节,且返回 EOF,若 err 是 nil,则返回 EOF
本方法永远返回 nil
(w *PipeWriter) Write(data []byte) (n int, err error)
本方法实现了标准 Write 接口:
它向管道中写入数据,阻塞直到一个活多个 reader 消耗所有的数据,或读取端被关闭
若读取端 is closed with an error,那么那个 err 作为 err 而返回;其他情况下 err 为 ErrClosedPipe
ReadCloser interface 类型
ReadCloser 是包含了基础 Read 和 Close 方法的接口类型
type ReadCloser interface {
Reader
Closer
}
ReadSeeker interface 类型
ReadSeeker 是包含了基础 Read 和 Seek 方法的接口类型
type ReadSeeker interface {
Reader
Seeker
}
ReadWriteCloser interface 类型
ReadWriteCloser 是包含了基础 Read Write 和 Close 方法的接口类型
ReadWriteCloser interface {
Reader
Writer
Closer
}
ReadWriteSeeker interface 类型
ReadWriteSeeker 是包含了基础 Read Write 和 Seek 方法的接口类型
type ReadWriteSeeker interface {
Reader
Writer
Seeker
}
ReadWriter interface 类型
ReadWriter 是包含了基础 Read 和 Write 方法的接口类型
type ReadWriter interface {
Reader
Writer
}
Reader interface 类型
Reader 是包裹了基本 Read 方法的接口类型
Read 读取至 len(p) 字节的数据至 p 中
它返回读取的字节数(0 <= n <= len(p)),以及任何遇到的错误
即便 Read 返回的 n 小于 len(p),它也可能会在被调用时,使用所有的 p 作为启动空间
若存在数据,但长度小于 len(p) 字节,Read 通常会返回现有的,而并不会等待更多的数据
当 Read 遇到一个错误,或者成功读取至少一个字节之后遇到 EOF,它都会返回已经读取的字节数
它可能会在同一次调用中返回(非 nil 的)错误,或在下一次调用中返回错误(以及 n == 0)
这个通常情况的一个实例就是,一个 Reader 在读取到了输入流结尾处,返回了一个非零字节数,以及一个可能是 EOF 或者 nil 的 err
那么在下次调用 Read 时,它应该返回 0,EOF
调用者应该永远优先考虑返回的 n > 0 字节,再考虑错误 err
这样做能正确地处理在读取了一些字节之后遇到的 I/O 错误,同时也允许了 EOF 的行为
Read 的实现并不鼓励返回 0 字节长度的同时返回 nil 错误,除了 len(p) == 0 的情况
调用者应该对待返回的 0 和 nil 为指示什么事情也没有发生;特别是,它并未指示出 EOF 来
实现禁止持有 p
type Reader interfaec {
Read(p []byte) (n int, err error)
}
LimitReader(r Reader, n int64) Reader
返回一个 Reader,从 r 去读数据,但在读取了 n 字节之后,以 EOF 停止
底层的实现为一个 *LimitedReader
EG.
r := strings.NewReader("some io.Reader stream to be read\n")
lr := io.LimitReader(r, 4)
if _, err := io.Copy(os.Stdout, lr); err != nil {
log.Fatal(err)
}
MultiReader(reader ...Reader) Reader
返回一个 Reader,它们是所提供的 Reader 的逻辑上的串联
它们按顺序读取
一旦所有的输入都返回 EOF,Read 将返回 EOF
若任何 reader 返回了一个 非 nil 非 EOF 的错误,Read 将返回那个错误
EG.
r1 := strings.NewReader("first reader ")
r2 := strings.NewReader("second reader ")
r3 := strings.NewReader("third reader\n")
r := io.MultiReader(r1, r2, r3)
if _, err := io.Copy(os.Stdout, r); err != nil {
log.Fatal(err)
}
TeeReader(r Reader, w Writer) Reader
返回一个 Reader,它将任何从 r 中读取的数据都写入 w 中
所有通过该函数,从 r 读取的数据,都会顺次写入 w 中
没有内部缓存——任何写入都应该在读取结束之前结束
任何在写入时遇到的错误都会回报为读取错误
EG.
r := strings.NewReader("some io.Reader stream to be read\n")
var buf bytes.Buffer
tee := io.TeeReader(r, &buf)
printall := func(r io.Reader) {
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", b)
}
printall(tee)
printall(&buf)
ReaderAt interface 类型
ReaderAt 是包裹了基本 ReadAt 方法的接口类型
ReadAt 从底层输入源的偏移 off 处开始,读取 len(p) 字节的数据至 p 中
它返回已读取的字节数(0 <= n <= len(p)),以及任何遇到的错误
当 ReadAt 返回 n < len(p) 时,它返回一个非 nil 的错误来解释为什么没有更多的字节被返回
在这个层面上来说,ReadAt 比 Read 更严格
即便 Read 返回的 n 小于 len(p),它也可能会在被调用时,使用所有的 p 作为启动空间
若存在数据,但长度小于 len(p) 字节,ReadAt 会阻塞直到所有数据可用,或者遇到一个错误
在这个层面上来说,ReadAt 与 Read 是不同的
若返回的 n == len(p),且 ReadAt 到达输入源的末尾,ReadAt 既可以返回 err == EOF,也可以返回 err == nil
若 ReadAt 从具有 seek offset 的输入源读取数据,
ReadAt 应该不去影响底层的 seek offset,也不受底层的 seek offset影响
ReadAt 的客户端应该可以并行地对同一个输入源调用 ReadAt
实现禁止持有 p
type ReaderAt interface {
ReadAt(p []byte, off int64) (n int, err error)
}
ReaderFrom interface 类型
ReaderFrom 是包裹了基本 ReadFrom 方法的接口类型
ReadFrom 从 r 中读取数据,直到 EOF 或错误
返回值 n 是已经读取到的数据
在读取过程中,任何错误,除了 io.EOF,都会被返回
若可用,则 Copy 函数使用改方法
type ReaderFrom interface {
ReadFrom(r Reader) (n int64, err error)
}
RuneReader interface 类型
RuneReader 是包裹了基本的 ReadRune 方法的接口类型
ReadRune 从读取单个 UTF-8 编码的 Unicode 字符,并返回对应的 rune 和 它的字节大小
若没有可用的字符,err 将被设置
type RuneReader interface {
ReadRune() (r rune, size int, err error)
}
RuneScanner interface 类型
RuneScanner 为将 UnreadRune 方法加入基本的 ReadRune 方法的接口类型
UnreadRune 导致下次调用 ReadRune 时,返回和上次调用 ReadRune 相同的值
连续两次调用 UnreadRune 之间没有调用 ReadRune 可能会产生错误
type RuneScanner interface {
RuneReader
UnreadRune() error
}
SectionReader struct 类型
SectionReader 在底层 ReaderAt 的某个切片上,实现了 Read Seek ReadAt
type SectionReader struct {
// 包含过滤的或未导出的字段
}
EG.
r := strings.NewReader("some io.Reader stream to be read\n")
s := io.NewSectionReader(r, 5, 17)
if _, err := io.Copy(os.Stdout, s); err != nil {
log.Fatal(err)
}
NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader
返回一个 SectionReader,其从 r 的偏移 off 开始,读取 n 字节之后,以 EOF 结束
(s *SectionReader) Read(p []byte) (n int, err error)
(s *SectionReader) ReadAt(p []byte, off int64) (n int, err error)
EG.
r := strings.NewReader("some io.Reader stream to be read\n")
s := io.NewSectionReader(r, 5, 16)
buf := make([]byte, 6)
if _, err := s.ReadAt(buf, 10); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", buf)
(s *SectionReader) Seek(offset int64, whence int) (int64, error)
EG.
r := strings.NewReader("some io.Reader stream to be read\n")
s := io.NewSectionReader(r, 5, 16)
if _, err := s.Seek(10, io.SeekStart); err != nil {
log.Fatal(err)
}
buf := make([]byte, 6)
if _, err := s.Read(buf); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", buf)
(s *SectionReader) Size() int64
返回当前 Section 的大小的字节数
Seeker interface 类型
Seeker 是包裹了基本 Seek 方法的接口类型
Seek 设置了下一次 Read 或 Write 的偏移值,根据 whence 来解读相对位置:
SeekStart 意味着相对于文件开头,
SeekCurrent 意味着相对当前偏移
SeekEnd 意味着相对文件结尾
Seek 返回新的相对于文件开头的偏移值,若有错误也一并返回
查找一个位于文件起始位置前的偏移是一个错误
查找任何正向偏移是有效的,但随后的对于底层对象的 I/O 操作的行为,则根据实现的不同而不同
type Seeker interface {
Seek(offset int64, whence int) (int64, error)
}
WriteCloser interface 类型
WriteCloser 是包裹了基本的 Write 和 Close 方法的接口类型
type WriteCloser interface {
Writer
Closer
}
WriteSeeker interface 类型
WriteSeeker 是包裹了基本的 Write 和 Seek 方法的接口类型
type WriteSeeker interface {
Writer
Seeker
}
Writer interface 类型
Writer 是包裹了基本的 Write 方法的接口类型
Write 从 p 中写入 len(p) 字节的数据至底层数据流
它返回从 p 写入的字节的数量(0 <= n <= len(p)),以及任何任何导致写入提前终止的错误
若 n < len(p), Write 必须返回一个非 nil 的错误
Write 禁止修改数据切片,即便是临时的也不行
实现禁止持有 p
type Writer interface {
Write(p []byte) (n int, err error)
}
MultiWriter(writers ...Writer) Writer
创建一个 writer,将其自身写入的数据拷贝至所有提供的 writer 中,与 Unix 的 tee(1) 命令类似
EG.
r := strings.NewReader("some io.Reader stream to be read\n")
var buf1, buf2 bytes.Buffer
w := io.MultiWriter(&buf1, &buf2)
if _, err := io.Copy(w, r); err != nil {
log.Fatal(err)
}
fmt.Print(buf1.String())
fmt.Print(buf2.String())
WriterAt interface 类型
WriterAt 是包裹了基本的 WriteAt 方法的接口类型
WriteAt 在底层数据流的偏移 off 处,写入从 p 取得的中长度为 len(p) 字节的数据
它返回从 p 写入的字节的数量(0 <= n <= len(p)),以及任何导致写入提前终止的错误
若 n < len(p), Write 必须返回一个非 nil 的错误
若 WriteAt 写入的目标具有 seek offset,WriteAt 不应该影响底层的 seek offset,也不应该被底层的 seek offset 所影响
WriteAt 的客户端可以并行运行 WriteAt 在相同的目标,只要它们的范围没有交叠
实现禁止持有 p
type WriterAt interface {
WriteAt(p []byte, off int64) (n int, err error)
}
WriterTo interface 类型
WriterTo 是包裹了 WriteTo 方法的接口类型
WriteTo 写入数据至 w 中,直到没有更多数据可写入,或者遇见了一个错误
返回值 n 是写入的字节数量
任何写入过程中遇见的错误也将一同被返回
若存在,则 Copy 函数会使用 WriteTo 方法
type WriterTo interface {
WriteTo(w Writer) (n int64, err error)
}