go io的一些解析
本次打算对go的io进行一个分析。
go io
首先我们来查看一下go io包下的文件树。
1 |
|
ioutil
是一些工具,fs
则是go1.16
加入的对文件系统相关的包。
所以这里我们首先来看看io.go
。
其中包含四个最基础的接口。
1 |
|
当然还有非常多的组合接口。
1 |
|
这些都是go不错的设计理念,设计小接口,通过小接口组合出大接口。
接下来我们来看看其中给的一些io struct
的设计。
LimitedReader
1 |
|
这个主要是限制你只能读文件的n个字节。比如下面的方法第二次读就返回error了
1 |
|
SectionReader
1 |
|
这个主要实现的是ReaderAt
接口。
1 |
|
我们来看看SectionReader
实现大概就明白其主要作用了。其主要就是提供两种Read方法,一种是使用内部off,一种是使用外部off。
- Seek 方法主要是随机到区间的某个位置。
- ReadAt方法则是通过参数指定偏移量来读取。
- Read方法偏移量s.base+off读取数据到p中。
也就是提供了一个随机读取的能力和块读取的能力。接下来可以看看io包是如何测试他的。前面主要是测试seek方法工作是否合理,主要是与bytes.NewReader进行比较。最后的是测试Read方法和ReadAt工作是否合理,因为ReadAt是从sr.off(100)的位置开始读,所以n返回值应该是0。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
27func TestSectionReader_Seek(t *testing.T) {
// Verifies that NewSectionReader's Seeker behaves like bytes.NewReader (which is like strings.NewReader)
br := bytes.NewReader([]byte("foo"))
sr := io.NewSectionReader(br, 0, int64(len("foo")))
for _, whence := range []int{io.SeekStart, io.SeekCurrent, io.SeekEnd} {
for offset := int64(-3); offset <= 4; offset++ {
brOff, brErr := br.Seek(offset, whence)
srOff, srErr := sr.Seek(offset, whence)
if (brErr != nil) != (srErr != nil) || brOff != srOff {
t.Errorf("For whence %d, offset %d: bytes.Reader.Seek = (%v, %v) != SectionReader.Seek = (%v, %v)",
whence, offset, brOff, brErr, srErr, srOff)
}
}
}
// And verify we can just seek past the end and get an EOF
got, err := sr.Seek(100, io.SeekStart)
if err != nil || got != 100 {
t.Errorf("Seek = %v, %v; want 100, nil", got, err)
}
n, err := sr.Read(make([]byte, 10))
if n != 0 || err != io.EOF {
t.Errorf("Read = %v, %v; want 0, EOF", n, err)
}
}
整个struct就是提供一个区间读取的能力。
OffsetWriter
1 |
|
- Write方法 o.off 位置写入p。同时o.off + len(p)
- WriteAt方法则是从s.base+off位置写入怕,但是o.off不变。
- Seek泽合SectionReader一样,随机到一个位置。
目前看来其主要提供的能力就是偏移写入。这可以来写大文件,分割开写,并发安全。第一个routine写前100个byte,第二个routine写100-200个byte。
go io/fs
TODO
参考链接
go io的一些解析
https://silky1313.github.io/2025/01/31/go_io/