io

io

https://pkg.go.dev/io@go1.20.1

​ io包提供了基本的I/O原语接口。它的主要任务是将这些原语的现有实现(例如os包中的实现)封装到共享的公共接口中,以抽象功能,以及一些其他相关的原语。

​ 由于这些接口和原语封装了具有各种实现的底层操作,除非另有通知,否则客户端不应假设它们适合并行执行。

常量

1
2
3
4
5
const (
	SeekStart   = 0 // 相对于文件的起点进行寻找
	SeekCurrent = 1 // 相对于当前偏移量进行寻找
	SeekEnd     = 2 // 相对于结尾进行寻找
)

Seek whence values.

在Go语言中,Seek方法的whence参数用于确定相对于哪个位置进行偏移量的计算。

变量

1
var EOF = errors.New("EOF")

​ EOF 是 Read方法在没有更多输入可用时返回的错误。(Read方法必须自己返回 EOF,而不是封装 EOF 的错误,因为调用者将使用 == 测试 EOF。)函数只应返回 EOF 来表示输入的优雅结束。如果 EOF 在结构化数据流中意外发生,则适当的错误是 ErrUnexpectedEOF 或提供更多详细信息的其他错误。

1
var ErrClosedPipe = errors.New("io: read/write on closed pipe")

​ ErrClosedPipe是在关闭的管道上进行读取或写入操作时使用的错误。

1
var ErrNoProgress = errors.New("multiple Read calls return no data or error")

​ ErrNoProgress 是一些 Reader 的客户端在多次调用 Read 后未返回任何数据或错误时返回的错误,通常表明 Reader 实现有问题。

1
var ErrShortBuffer = errors.New("short buffer")

​ ErrShortBuffer表示读取所需的缓冲区比提供的缓冲区要长。

1
var ErrShortWrite = errors.New("short write")

​ ErrShortWrite表示写入接受的字节数比请求的字节数少,但未返回明确的错误。

1
var ErrUnexpectedEOF = errors.New("unexpected EOF")

​ ErrUnexpectedEOF表示在读取固定大小的块或数据结构的过程中遇到了EOF。

函数

func Copy

1
func Copy(dst Writer, src Reader) (written int64, err error)

​ Copy函数从src复制到dst,直到在src上到达EOF或发生错误。它返回复制的字节数和在复制过程中遇到的第一个错误(如果有)。

​ 成功的Copy返回err==nil,而不是err==EOF。因为Copy定义为从src读取直到EOF,所以它不会将从Read返回的EOF视为要报告的错误。

​ 如果src实现了WriterTo接口,则通过调用src.WriteTo(dst)来实现复制。否则,如果dst实现了ReaderFrom接口,则通过调用dst.ReadFrom(src)来实现复制。【如果src和dst都实现了所说的,以哪个为准?】

Copy Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")

	if _, err := io.Copy(os.Stdout, r); err != nil {
		log.Fatal(err)
	}

}
Output:

some io.Reader stream to be read

func CopyBuffer <- go1.5

1
func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error)

​ CopyBuffer函数与Copy函数相同,只是它通过提供的缓冲区(如果需要)进行阶段处理,而不是分配临时缓冲区。如果buf为nil,则会分配一个;否则,如果长度为零,则CopyBuffer函数会出现panic。

​ 如果src实现了WriterTo或dst实现了ReaderFrom,则不会使用buf执行复制。

CopyBuffer Example
 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
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	r1 := strings.NewReader("first reader\n")
	r2 := strings.NewReader("second reader\n")
	buf := make([]byte, 8)

	// buf is used here...
	if _, err := io.CopyBuffer(os.Stdout, r1, buf); err != nil {
		log.Fatal(err)
	}

	// ... reused here also. No need to allocate an extra buffer.
	if _, err := io.CopyBuffer(os.Stdout, r2, buf); err != nil {
		log.Fatal(err)
	}

}
Output:

first reader
second reader

func CopyN

1
func CopyN(dst Writer, src Reader, n int64) (written int64, err error)

​ CopyN函数从src复制n个字节(或直到出现错误)到dst。它返回已复制的字节数和在复制过程中遇到的最早的错误。如果err == nil,则written == n。

​ 如果dst实现了ReaderFrom接口,则使用它来实现复制。

CopyN Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read")

	if _, err := io.CopyN(os.Stdout, r, 4); err != nil {
		log.Fatal(err)
	}

}
Output:

some

func Pipe

1
func Pipe() (*PipeReader, *PipeWriter)

​ Pipe创建一个同步的内存管道。它可用于连接期望io.Reader的代码与期望io.Writer的代码。

​ 在管道上的读取和写入是一对一匹配的,除非需要多个读取来消耗单个写入。也就是说,每次对PipeWriter的写入都会阻塞,直到它满足了来自PipeReader的一个或多个读取,这些读取完全消耗了已写入的数据。数据直接从写入到相应的读取(或读取)中复制;没有内部缓冲。

​ 在并行调用Read和Write或与Close一起调用是安全的。并行调用Read和并行调用Write也是安全的:各个调用将依次进行。

Pipe Example
 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
package main

import (
	"fmt"
	"io"
	"log"
	"os"
)

func main() {
	r, w := io.Pipe()

	go func() {
		fmt.Fprint(w, "some io.Reader stream to be read\n")
		w.Close()
	}()

	if _, err := io.Copy(os.Stdout, r); err != nil {
		log.Fatal(err)
	}

}
Output:

some io.Reader stream to be read

func ReadAll <- go1.16

1
func ReadAll(r Reader) ([]byte, error)

​ ReadAll函数从r读取直到出现错误或EOF,并返回它读取的数据。成功调用返回err == nil,而不是err == EOF。因为ReadAll函数定义为从src读取直到EOF,所以它不会将从Read中读取的EOF视为错误报告。

ReadAll Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("Go is a general-purpose language designed with systems programming in mind.")

	b, err := io.ReadAll(r)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s", b)

}
Output:

Go is a general-purpose language designed with systems programming in mind.

func ReadAtLeast

1
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)

​ ReadAtLeast函数从r中读取到buf,直到它读取至少min个字节。它返回已复制的字节数和错误(如果读取的字节数少于min个)。如果没有读取任何字节,则错误为EOF。如果在读取少于min个字节后出现EOF,则ReadAtLeast返回ErrUnexpectedEOF。如果min大于buf的长度,则ReadAtLeast返回ErrShortBuffer。返回时,当且仅当err == nil时,n >= min。如果r在读取至少min个字节后返回错误,则将删除该错误。

ReadAtLeast Example
 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
package main

import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")

	buf := make([]byte, 14)
	if _, err := io.ReadAtLeast(r, buf, 4); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s\n", buf)

	// buffer smaller than minimal read size.
	shortBuf := make([]byte, 3)
	if _, err := io.ReadAtLeast(r, shortBuf, 4); err != nil {
		fmt.Println("error:", err)
	}

	// minimal read size bigger than io.Reader stream
	longBuf := make([]byte, 64)
	if _, err := io.ReadAtLeast(r, longBuf, 64); err != nil {
		fmt.Println("error:", err)
	}

}
Output:

some io.Reader
error: short buffer
error: unexpected EOF

func ReadFull

1
func ReadFull(r Reader, buf []byte) (n int, err error)

​ ReadFull函数从r中精确地读取len(buf)个字节到buf中。它返回已复制的字节数和错误(如果读取的字节数少于len(buf)个)。如果没有读取任何字节,则错误为EOF。如果在读取一些但不是所有字节后出现EOF,则ReadFull函数返回ErrUnexpectedEOF。返回时,当且仅当err == nil时,n == len(buf)。如果r在读取至少len(buf)个字节后返回错误,则将删除该错误。

ReadFull Example
 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
package main

import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	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)

	// minimal read size bigger than io.Reader stream
	longBuf := make([]byte, 64)
	if _, err := io.ReadFull(r, longBuf); err != nil {
		fmt.Println("error:", err)
	}

}
Output:

some
error: unexpected EOF

func WriteString

1
func WriteString(w Writer, s string) (n int, err error)

​ WriteString函数将字符串s的内容写入接受字节片的w中。如果w实现了StringWriter,则直接调用其WriteString方法。否则,将调用w.Write一次。

WriteString Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package main

import (
	"io"
	"log"
	"os"
)

func main() {
	if _, err := io.WriteString(os.Stdout, "Hello World"); err != nil {
		log.Fatal(err)
	}

}
Output:

Hello World

类型

type ByteReader

1
2
3
type ByteReader interface {
	ReadByte() (byte, error)
}

​ ByteReader是封装了ReadByte方法的接口。

​ ReadByte读取并返回输入中的下一个字节或遇到的任何错误。如果ReadByte返回错误,则没有输入字节被消耗,返回的字节值未定义。

​ ReadByte提供了逐字节处理的有效接口。如果Reader未实现ByteReader,则可以使用bufio.NewReader进行封装以添加此方法。

type ByteScanner

1
2
3
4
type ByteScanner interface {
	ByteReader
	UnreadByte() error
}

​ ByteScanner是在基本ReadByte方法上添加了UnreadByte方法的接口。

​ UnreadByte方法使得下一次调用ReadByte方法返回上次读取的最后一个字节。如果上次操作不是对ReadByte方法的成功调用,则UnreadByte方法可能会返回错误,未读取最后一个字节(或上一个未读取字节),或(在支持Seeker接口的实现中)将偏移量设置为当前偏移量前一个字节。

type ByteWriter <- go1.1

1
2
3
type ByteWriter interface {
	WriteByte(c byte) error
}

​ ByteWriter是封装了WriteByte方法的接口。

type Closer

1
2
3
type Closer interface {
	Close() error
}

​ Closer是封装了基本Close方法的接口。

​ 第一次调用Close方法后的行为是未定义的。具体的实现可能会记录自己的行为。

type LimitedReader

1
2
3
4
type LimitedReader struct {
	R Reader // 底层的 Reader
	N int64  // 最多可以读取的字节数
}

​ LimitedReader结构体从 R 中读取数据,但是限制了返回数据的数量,只有最多 N 个字节。每次调用 Read 都会更新 N 的值以反映新的剩余字节数。当 N <= 0 或者底层的 R 返回 EOF 时,Read 会返回 EOF。

(*LimitedReader) Read

1
func (l *LimitedReader) Read(p []byte) (n int, err error)

type OffsetWriter <- go1.20

1
2
3
4
type OffsetWriter struct {
	// contains filtered or unexported fields
    // 包含已过滤或未导出的字段
}

​ OffsetWriter结构体将写入基于 offset 的数据映射到底层 Writer 中基于 base+off 的偏移位置。

func NewOffsetWriter <- go1.20

1
func NewOffsetWriter(w WriterAt, off int64) *OffsetWriter

​ NewOffsetWriter函数返回一个 OffsetWriter,它从 offset 位置开始写入 w。

(*OffsetWriter) Seek <- go1.20

1
func (o *OffsetWriter) Seek(offset int64, whence int) (int64, error)

(*OffsetWriter) Write <- go1.20

1
func (o *OffsetWriter) Write(p []byte) (n int, err error)

(*OffsetWriter) WriteAt <- go1.20

1
func (o *OffsetWriter) WriteAt(p []byte, off int64) (n int, err error)

type PipeReader

1
2
3
4
type PipeReader struct {
	// contains filtered or unexported fields
    // 包含已过滤或未导出的字段
}

​ PipeReader结构体是管道的读取端。

(*PipeReader) Close

1
func (r *PipeReader) Close() error

​ Close方法关闭读取器;后续对管道写入端的写入将返回 ErrClosedPipe 错误。

(*PipeReader) CloseWithError

1
func (r *PipeReader) CloseWithError(err error) error

​ CloseWithError方法关闭读取器;后续对管道写入端的写入将返回 err 错误。

​ 如果存在先前的错误,CloseWithError不会覆盖它并始终返回nil。

(*PipeReader) Read

1
func (r *PipeReader) Read(data []byte) (n int, err error)

​ Read方法实现标准的Read接口:它从管道中读取数据,在写入方到达或写入端关闭之前阻塞。如果写入端以错误关闭,则将该错误作为err返回;否则err为EOF。

type PipeWriter

1
2
3
4
type PipeWriter struct {
	// contains filtered or unexported fields
    // 包含已过滤或未导出的字段
}

​ PipeWriter结构体是管道的写入方。

(*PipeWriter) Close

1
func (w *PipeWriter) Close() error

​ Close关闭写入器;随后从读取器读取数据将不会返回字节和EOF。

(*PipeWriter) CloseWithError

1
func (w *PipeWriter) CloseWithError(err error) error

​ CloseWithError方法关闭写入器;随后从读取器读取数据将不会返回字节和错误err,如果err为nil,则返回EOF。

​ 如果存在先前的错误,CloseWithError不会覆盖它并始终返回nil。

(*PipeWriter) Write

1
func (w *PipeWriter) Write(data []byte) (n int, err error)

​ Write方法实现标准的Write接口:它将数据写入管道,阻塞直到一个或多个读取器消耗了所有数据或读取端关闭。如果读取端以错误关闭,则将该err返回;否则err为ErrClosedPipe。

type ReadCloser

1
2
3
4
type ReadCloser interface {
	Reader
	Closer
}
ReadCloser接口组合了基本的Read和Close方法。

func NopCloser <- go1.16

1
func NopCloser(r Reader) ReadCloser

​ NopCloser函数返回一个带有no-op Close方法的ReadCloser,封装提供的Reader r。如果r实现了WriterTo,则返回的ReadCloser将通过转发调用来实现WriterTo方法。

type ReadSeekCloser <- go1.16

1
2
3
4
5
type ReadSeekCloser interface {
	Reader
	Seeker
	Closer
}

​ ReadSeekCloser接口组合了基本的Read、Seek和Close方法。

type ReadSeeker

1
2
3
4
type ReadSeeker interface {
	Reader
	Seeker
}

​ ReadSeeker接口组合了基本的Read、Seek方法。

type ReadWriteCloser

1
2
3
4
5
type ReadWriteCloser interface {
	Reader
	Writer
	Closer
}

​ ReadWriteCloser接口组合了基本的Read、Write和Close方法。

type ReadWriteSeeker

1
2
3
4
5
type ReadWriteSeeker interface {
	Reader
	Writer
	Seeker
}

​ ReadWriteSeeker接口组合了基本的Read、Write和Seek方法。

type ReadWriter

1
2
3
4
type ReadWriter interface {
	Reader
	Writer
}

​ ReadWriter接口组合了基本的Read和Write方法。

type Reader

1
2
3
type Reader interface {
	Read(p []byte) (n int, err error)
}

​ Reader接口封装了基本的Read方法。

​ Read方法将最多len(p)个字节读取到p中。它返回读取的字节数(0 <= n <= len(p))以及任何遇到的错误。即使Read返回n < len(p),它也可以在调用期间使用p作为临时空间。如果一些数据可用但不足len(p)字节,则Read通常返回可用的内容而不是等待更多。

​ 当Read方法在成功读取n > 0个字节后遇到错误或文件结束条件时,它返回读取的字节数。它可能从同一调用返回(非零)错误,也可能从后续调用返回错误(n == 0)。一般情况下,一个返回非零字节数并在输入流结束时返回EOF或nil错误的Reader实例,下一次Read应该返回0,EOF。

​ 在考虑错误err之前,调用者应始终处理返回的n > 0字节。这样做可以正确处理在读取一些字节之后发生的I/O错误,以及两种允许的EOF行为。

​ 实现Read的方法不应该返回具有nil错误的零字节计数,除非len(p) == 0。调用者应该将返回0和nil视为表示没有发生任何事情;特别是它不表示EOF。

​ 实现不能保留p。

func LimitReader

1
func LimitReader(r Reader, n int64) Reader

​ LimitReader函数返回一个从 r 读取但在读取 n 个字节后停止并返回 EOF 的 Reader。底层实现是一个 *LimitedReader

LimitReader Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	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)
	}

}
Output:

some

func MultiReader

1
func MultiReader(readers ...Reader) Reader

​ MultiReader函数返回一个 Reader,它是提供的输入 readers 的逻辑连接。它们按顺序读取。一旦所有输入都返回 EOF,Read 将返回 EOF。如果任何读取器返回非 nil、非 EOF 错误,则 Read 将返回该错误。

MultiReaderExample
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	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)
	}

}
Output:

first reader second reader third reader

func TeeReader

1
func TeeReader(r Reader, w Writer) Reader

​ TeeReader函数返回一个 Reader,它从 r 中读取并将其写入 w。通过它执行的所有对 r 的读取都将与对 w 的相应写入匹配。没有内部缓冲区——写入必须在读取完成之前完成。任何在写入时遇到的错误都将作为读取错误报告。

TeeReader Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	var r io.Reader = strings.NewReader("some io.Reader stream to be read\n")

	r = io.TeeReader(r, os.Stdout)

	// Everything read from r will be copied to stdout.
	if _, err := io.ReadAll(r); err != nil {
		log.Fatal(err)
	}

}
Output:

some io.Reader stream to be read

type ReaderAt

1
2
3
type ReaderAt interface {
	ReadAt(p []byte, off int64) (n int, err error)
}

​ ReaderAt 是封装基本 ReadAt 方法的接口。

​ ReadAt方法从基础输入源的偏移量 off 开始将 len(p) 个字节读入 p 中。它返回读取的字节数(0 <= n <= len(p))和任何遇到的错误。

​ 当 ReadAt方法返回 n < len(p) 时,它返回一个非 nil 的错误,解释为什么没有返回更多的字节。在这方面,ReadAt方法比 Read方法更严格。

​ 即使 ReadAt方法返回 n < len(p),它也可以在调用期间使用 p 中的所有字节作为临时空间。如果有一些数据可用但不是 len(p) 字节,则 ReadAt 阻塞,直到所有数据都可用或发生错误。在这方面,ReadAt 不同于 Read。

​ 如果 ReadAt方法返回的 n = len(p) 字节在输入源的末尾,则 ReadAt 可能返回 err == EOF 或 err == nil。

​ 如果 ReadAt方法从具有 seek 偏移量的输入源中读取,则 ReadAt方法不应影响底层 seek 偏移量,也不应受其影响。

​ ReadAt方法的客户端可以在同一输入源上并行执行 ReadAt方法调用。

​ 实现不得保留 p。

type ReaderFrom

1
2
3
type ReaderFrom interface {
	ReadFrom(r Reader) (n int64, err error)
}

​ ReaderFrom 是封装 ReadFrom 方法的接口。

​ ReadFrom方法从 r 中读取数据,直到 EOF 或错误。返回值 n 是读取的字节数。除了 EOF 之外,在读取过程中遇到的任何错误也将返回。

​ 如果可用,Copy函数将使用 ReaderFrom方法。

type RuneReader

1
2
3
type RuneReader interface {
	ReadRune() (r rune, size int, err error)
}

​ RuneReader 是封装了 ReadRune 方法的接口。

​ ReadRune方法读取一个单一的编码的 Unicode 字符并返回该字符以及其所占用的字节数。如果没有字符可用,则 err 将被设置。

type RuneScanner

1
2
3
4
type RuneScanner interface {
	RuneReader
	UnreadRune() error
}

​ RuneScanner 是在基本 ReadRune 方法上添加了 UnreadRune 方法的接口。

​ UnreadRune方法会导致下一次调用 ReadRune方法返回上次读取的最后一个字符。如果上次操作不是成功的 ReadRune方法调用,则 UnreadRune方法可能会返回错误、未读取最后一个字符(或最后一个未读取字符之前的字符),或者(在支持 Seeker 接口的实现中)定位到当前偏移量之前的字符的开头。

type SectionReader

1
2
3
4
type SectionReader struct {
	// contains filtered or unexported fields
    // 包含已过滤或未导出的字段
}

​ SectionReader 在底层的 ReaderAt方法的一部分实现了 Read、Seek 和 ReadAt方法。

SectionReader Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	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)
	}

}
Output:

io.Reader stream

func NewSectionReader

1
func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader

​ NewSectionReader函数返回一个 SectionReader,该 Reader 从偏移量 off 处开始从 r 读取并在 n 字节后以 EOF 结束。

(*SectionReader) Read

1
func (s *SectionReader) Read(p []byte) (n int, err error)
Read Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")
	s := io.NewSectionReader(r, 5, 17)

	buf := make([]byte, 9)
	if _, err := s.Read(buf); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s\n", buf)

}
Output:

io.Reader

(*SectionReader) ReadAt

1
func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err error)
ReadAt Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")
	s := io.NewSectionReader(r, 5, 17)

	buf := make([]byte, 6)
	if _, err := s.ReadAt(buf, 10); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s\n", buf)

}
Output:

stream

(*SectionReader) Seek

1
func (s *SectionReader) Seek(offset int64, whence int) (int64, error)
Seek Example
 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
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")
	s := io.NewSectionReader(r, 5, 17)

	if _, err := s.Seek(10, io.SeekStart); err != nil {
		log.Fatal(err)
	}

	if _, err := io.Copy(os.Stdout, s); err != nil {
		log.Fatal(err)
	}

}
Output:

stream

(*SectionReader) Size

1
func (s *SectionReader) Size() int64

​ Size方法返回该 SectionReader 中字节的大小。

Size Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package main

import (
	"fmt"
	"io"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")
	s := io.NewSectionReader(r, 5, 17)

	fmt.Println(s.Size())

}
Output:

17

type Seeker

1
2
3
type Seeker interface {
	Seek(offset int64, whence int) (int64, error)
}

​ Seeker 是封装基本 Seek 方法的接口。

​ Seek方法设置下一个 Read 或 Write 的偏移量,根据 whence 进行解释:SeekStart 表示相对于文件的开头,SeekCurrent 表示相对于当前偏移量,SeekEnd 表示相对于结尾(例如,offset = -2 表示文件的倒数第二个字节)。Seek 返回相对于文件开头的新偏移量,或者如果有的话,返回错误。

​ 寻找到文件开头之前的偏移量是一个错误。寻找任何正偏移量可能是允许的,但是如果新的偏移量超过底层对象的大小,则随后的 I/O 操作的行为取决于实现。

type StringWriter <- go1.12

1
2
3
type StringWriter interface {
	WriteString(s string) (n int, err error)
}

​ StringWriter 是封装 WriteString 方法的接口。

type WriteCloser

1
2
3
4
type WriteCloser interface {
	Writer
	Closer
}

​ WriteCloser 是组合基本的 Write 和 Close 方法的接口。

type WriteSeeker

1
2
3
4
type WriteSeeker interface {
	Writer
	Seeker
}

​ WriteSeeker 是组合基本的 Write 和 Seek 方法的接口。

type Writer

1
2
3
type Writer interface {
	Write(p []byte) (n int, err error)
}

​ Writer 是封装基本 Write 方法的接口。

​ Write方法从 p 中写入 len(p) 个字节到基础数据流中。它返回从 p 中写入的字节数 n(0 <= n <= len(p))和任何导致写入提前停止的错误。如果它返回 n < len(p),则 Write 必须返回非 nil 错误。Write 必须不修改切片数据,即使是暂时的也不行。

​ 实现不得保留p。

1
var Discard Writer = discard{}

​ Discard 是一个 Writer,所有的写入调用都会成功地且不进行任何操作。

func MultiWriter

1
func MultiWriter(writers ...Writer) Writer

​ MultiWriter函数创建一个将其写入复制到所有提供的 writer 的 writer,类似于 Unix 的 tee(1) 命令。

​ 每个写入都写入到每个列出的 writer 中,一个接一个地。如果列出的 writer 返回错误,整个写操作将停止并返回该错误;不会继续下一个 writer。

MultiWriter Example
 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
package main

import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")

	var buf1, buf2 strings.Builder
	w := io.MultiWriter(&buf1, &buf2)

	if _, err := io.Copy(w, r); err != nil {
		log.Fatal(err)
	}

	fmt.Print(buf1.String())
	fmt.Print(buf2.String())

}
Output:

some io.Reader stream to be read
some io.Reader stream to be read

type WriterAt

1
2
3
type WriterAt interface {
	WriteAt(p []byte, off int64) (n int, err error)
}

​ WriterAt 是封装 WriteAt 方法的接口。

​ WriteAt方法从偏移量off处将长度为len(p)的p写入底层数据流。它返回写入的字节数(0 <= n <= len(p))和任何导致写入提前停止的错误。如果返回n < len(p),WriteAt必须返回非nil的错误。

​ 如果WriteAt方法正在向带有寻址偏移量的目标写入,则WriteAt方法不应受到影响,也不应影响基础寻址偏移量。

​ 如果WriteAt方法正在向目标写入数据,则客户端可以在同一目标上并行执行WriteAt方法调用,前提是范围不重叠。

​ 实现不得保留p。

type WriterTo

1
2
3
type WriterTo interface {
	WriteTo(w Writer) (n int64, err error)
}

​ WriterTo是封装WriteTo方法的接口。

​ WriteTo方法写入数据直到没有更多数据可写或出现错误。返回值n是写入的字节数。任何在写入期间遇到的错误也将返回。

​ 如果可用,Copy函数将使用WriterTo方法。