IO Streaming

Streaming IO in Go,引用此文,略有修改

io.Reader和io.Writer

io.Reader接口定义了从传输缓存读取数据

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

Read方法接受一个[]byte作为读取数据后的接收者,返回读取的字节数n和错误err,当读尽缓存内容时,err为io.EOF。

Read方法的读取机制

  1. 尽可能读取len(p)字节到p
  2. 调用Read()后,n可能比len(p)小
  3. 如果出现错误,read()仍可能返回缓冲区p中的n个字节。例如,读取突然关闭的TCP套接字。根据您的使用,您可以选择将字节保持在p中或重试。
  4. 当Read()读尽数据后,可能返回非零的n和err=io.EOF。甚至出现返回非零n和err=nil的情况,但是接下来的Read()方法调用一定返回n=0, err=io.EOF
  5. 当n=0,err=nil时,并不意味着读取数据完毕,接下来的Read()可能返回更多的数据。

综上,实现Read()方法还是比较棘手的,幸好标准库有好多实现了io.Reader的接口。

strings.NewReader
// NewReader returns a new Reader reading from s.
// It is similar to bytes.NewBufferString
// but more efficient and read-only.
func NewReader(s string) *Reader func main() {
reader := strings.NewReader("Clear is better than clever")
p := make([]byte, 4) for {
n, err := reader.Read(p)
if err != nil{
if err == io.EOF {
fmt.Println(string(p[:n])) //should handle any remainding bytes.
break
}
fmt.Println(err)
os.Exit(1)
}
fmt.Println(string(p[:n]))
}
}
自定义io.Reader

实现Read()方法,去除非字母

type alphaReader struct {
src string
cur int
} func newAlphaReader(src string) *alphaReader {
return &alphaReader{src: src}
} func alpha(r byte) byte {
if (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') {
return r
}
return 0
} func (a *alphaReader) Read(p []byte) (int, error) {
if a.cur >= len(a.src) {
return 0, io.EOF
} x := len(a.src) - a.cur
n, bound := 0, 0
if x >= len(p) {
bound = len(p)
} else if x <= len(p) {
bound = x
} buf := make([]byte, bound)
for n < bound {
if char := alpha(a.src[a.cur]); char != 0 {
buf[n] = char
}
n++
a.cur++
}
copy(p, buf) // 使用copy方法,保证切片每次读取指定大小的内容
return n, nil
} func main() {
reader := newAlphaReader("Hello! It's 9am, where is the sun?")
p := make([]byte, 4)
for {
n, err := reader.Read(p)
if err == io.EOF {
break
}
fmt.Print(string(p[:n]))
}
fmt.Println()
}

借助标准库的io.Reader实现来简化代码

type alphaReader struct {
reader io.Reader
} func newAlphaReader(reader io.Reader) *alphaReader {
return &alphaReader{reader: reader}
} func alpha(r byte) byte {
if (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') {
return r
}
return 0
} func (a *alphaReader) Read(p []byte) (int, error) {
n, err := a.reader.Read(p)
if err != nil {
return n, err
}
buf := make([]byte, n)
for i := 0; i < n; i++ {
if char := alpha(p[i]); char != 0 {
buf[i] = char
}
} copy(p, buf)
return n, nil
} func main() {
// use an io.Reader as source for alphaReader
reader := newAlphaReader(strings.NewReader("Hello! It's 9am, where is the sun?"))
p := make([]byte, 4)
for {
n, err := reader.Read(p)
if err == io.EOF {
break
}
fmt.Print(string(p[:n]))
}
fmt.Println()
}

与读取文件的io.Reader结合

func main() {
// use an os.File as source for alphaReader
file, err := os.Open("./alpha_reader3.go")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer file.Close() reader := newAlphaReader(file)
p := make([]byte, 4)
for {
n, err := reader.Read(p)
if err == io.EOF {
break
}
fmt.Print(string(p[:n]))
}
fmt.Println()
}

io.Writer

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

Write方法接受一个[]byte作为输入

func main() {
proverbs := []string{
"Channels orchestrate mutexes serialize",
"Cgo is not Go",
"Errors are values",
"Don't panic",
}
var writer bytes.Buffer for _, p := range proverbs {
n, err := writer.Write([]byte(p))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if n != len(p) {
fmt.Println("failed to write data")
os.Exit(1)
}
} fmt.Println(writer.String())
}
实现自定义io.Writer
type chanWriter struct {
ch chan byte
} func newChanWriter() *chanWriter {
return &chanWriter{make(chan byte, 1024)}
} func (w *chanWriter) Chan() <-chan byte {
return w.ch
} func (w *chanWriter) Write(p []byte) (int, error) {
n := 0
for _, b := range p {
w.ch <- b
n++
}
return n, nil
} func (w *chanWriter) Close() error {
close(w.ch)
return nil
} func main() {
writer := newChanWriter()
go func() {
defer writer.Close()
writer.Write([]byte("Stream "))
writer.Write([]byte("me!"))
}()
for c := range writer.Chan() {
fmt.Printf("%c", c)
}
fmt.Println()
}

chanWriter也实现了io.Closer, 调用writer.Close()关闭channel,避免chanWriter.Write

方法一直等待channel。

os.File

亦实现了io.Writer和io.Reader接口,因此向文件写文件可以调用writer.Write([]byte), os.Create返回*os.File

func main() {
proverbs := []string{
"Channels orchestrate mutexes serialize\n",
"Cgo is not Go\n",
"Errors are values\n",
"Don't panic\n",
}
// func Create(name string) (*File, error)
file, err := os.Create("./proverbs.txt")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer file.Close() for _, p := range proverbs {
n, err := file.Write([]byte(p))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if n != len(p) {
fmt.Println("failed to write data")
os.Exit(1)
}
}
fmt.Println("file write done")
}

os.Open返回的*os.File是只读的

func main() {
// 如果需要读写文件,使用os.OpenFile
// file, err := os.OpenFile("./proverbs.txt", os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644)
file, err := os.Open("./proverbs.txt")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer file.Close() p := make([]byte, 4)
for {
n, err := file.Read(p)
if err == io.EOF {
break
}
fmt.Print(string(p[:n]))
}
}

os.Stdout, os.Stdin, os.Stderr 其实也是*os.File

func main() {
proverbs := []string{
"Channels orchestrate mutexes serialize\n",
"Cgo is not Go\n",
"Errors are values\n",
"Don't panic\n",
} for _, p := range proverbs {
n, err := os.Stdout.Write([]byte(p))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if n != len(p) {
fmt.Println("failed to write data")
os.Exit(1)
}
}
}

io.Copy 方便的将流数据拷贝到目标reader

func main() {
proverbs := new(bytes.Buffer)
proverbs.WriteString("Channels orchestrate mutexes serialize\n")
proverbs.WriteString("Cgo is not Go\n")
proverbs.WriteString("Errors are values\n")
proverbs.WriteString("Don't panic\n") file, err := os.Create("./proverbs.txt")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer file.Close() // copy from reader data into writer file
if _, err := io.Copy(file, proverbs); err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("file created")
}
// 或者
func main() {
file, err := os.Open("./proverbs.txt")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer file.Close() if _, err := io.Copy(os.Stdout, file); err != nil {
fmt.Println(err)
os.Exit(1)
}
}

io.WriteString()

可以方便地将字符串写入到writer

func main() {
file, err := os.Create("./magic_msg.txt")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer file.Close()
if _, err := io.WriteString(file, "Go is fun!"); err != nil {
fmt.Println(err)
os.Exit(1)
}
}

Pipe writers and readers

输入io.PipeWriter和io.PipeReader模型IO操作,如在内存管道中。数据被写入管道的写入端,并使用单独的GO例程在管道的读取器端读取数据。

func main() {
proverbs := new(bytes.Buffer)
proverbs.WriteString("Channels orchestrate mutexes serialize\n")
proverbs.WriteString("Cgo is not Go\n")
proverbs.WriteString("Errors are values\n")
proverbs.WriteString("Don't panic\n") piper, pipew := io.Pipe() // write in writer end of pipe
go func() {
defer pipew.Close()
io.Copy(pipew, proverbs)
}() // read from reader end of pipe.
io.Copy(os.Stdout, piper)
piper.Close()
}

Buffered IO

GO通过包bufio支持缓冲IO,这使得使用文本内容更加容易。例如,下面的程序读取以值‘\n’分隔的逐行文件的内容。

func main() {
file, err := os.Open("./planets.txt")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer file.Close()
reader := bufio.NewReader(file) for {
line, err := reader.ReadString('\n')
if err != nil {
if err == io.EOF {
break
} else {
fmt.Println(err)
os.Exit(1)
}
}
fmt.Print(line)
} }

Util package

包ioutil是io的一个子包,它为IO提供了一些方便的功能。例如,以下代码使用函数ReadFile将文件的内容加载到[]byte中

package main

import (
"io/ioutil"
...
) func main() {
bytes, err := ioutil.ReadFile("./planets.txt")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("%s", bytes)
}

还有其他IO Stream 操作

  • file IO
  • buffered IO
  • network IO
  • formatted IO

golang IO streaming的更多相关文章

  1. 简析 Golang IO 包

    简析 Golang IO 包 io 包提供了 I/O 原语(primitives)的基本接口.io 包中定义了四个最基本接口 Reader.Writer.Closer.Seeker 用于表示二进制流的 ...

  2. golang io中io.go解读

    目录 1. 整体大纲 2. 接口 读 写 关闭 寻址 3. 函数 读 写 复制 4. 结构体 SectionReader LimitedReader teeReader 5. 备注 根据golang ...

  3. Golang IO包的妙用

    Golang 标准库对 IO 的抽象非常精巧,各个组件可以随意组合,可以作为接口设计的典范.这篇文章结合一个实际的例子来和大家分享一下. 背景 以一个RPC的协议包来说,每个包有如下结构 type P ...

  4. golang io需要牢记的几个点

    对于Reader比较麻烦需要记住以下: When Read encounters an error or end-of-file condition after successfully readin ...

  5. golang io.ReadFull

    buf := make([]byte, 10, 10) file, _ := os.Open("./data.txt") n, err := io.ReadFull(file, b ...

  6. 【Linux开发】IO streaming DMA buffer importing

    http://linuxtv.org/downloads/v4l-dvb-apis/dmabuf.html I/O流 (DMA缓存引用) 这是一个实验性接口,将来可能发生改变 DMABUF框架提供了在 ...

  7. golang io操作之写篇

    /** * @author livalon * @data 2018/9/4 15:11 */ package main import ( "os" "fmt" ...

  8. 实现golang io.Writer支持按照天为单位分割日志

    golang中的日志不支持按照天分割,很多开源的日志包都是只支持按照文件大小分割日志,不太利于生产环境中的使用.因此我实现了timewriter,支持: 实现按照天为单位分割日志,可以完美支持gola ...

  9. golang IO 流抽象与应用

    https://blog.csdn.net/pmlpml/article/details/82930191

随机推荐

  1. NC 部署问题

    1.was环境部署日志  IBM/WEBSPHERE/APPSERVER/PRORFILES/APPSRV01/LOGS/SERVER1/ 

  2. UI行业发展预测 & 系列规划的调整

    又双叒叕拖更了,上一篇还是1月22号更新的,这都3月9号了…… 前面几期把职业规划.能力分析.几个分析用的设计理论都写完了,当然实际工作中用到的方法论不止上面这些,后续会接着学习: 如果你的目标是一线 ...

  3. 高斯混合模型(GMM) - 混合高斯回归(GMR)

    http://www.zhihuishi.com/source/2073.html 高斯模型就是用高斯概率密度函数(正态分布曲线)精确地量化事物,将一个事物分解为若干的基于高斯概率密度函数(正态分布曲 ...

  4. js中的原型对象链

    由于原型对象也是一个对象,它也有自己的原型对象并继承对象中的属性,这就是原型对象链:对象继承其原型对象,而原型对象继承它的原型对象,以此类推. 我们创建的每一个函数都有一个prototype(原型)属 ...

  5. 《Linux就该这么学》第十三天课程

    使用Apache服务部署静态网站 原创地址:https://www.linuxprobe.com/chapter-10.html 今天学了Apache,这只是RHCE课程的开始,估计后面越来越难 今天 ...

  6. python语言相关语法基础

    numpy系列import numpya = numpy.array([[1,2], [3,4]])b = numpy.array([[5,6], [7,8]])a*b>>>arra ...

  7. appium:运行脚本时,报404的解决办法

    对于报404的错,不要怀疑,在环境正常的情况下,一定是你的端口被占用了. 就用:查看端口:netstat -aon|findstr 5037 查看进程:tasklist /fi "PID e ...

  8. jenkins maven git windows code 自动部署

    本人刚刚接触  写的不好就对付看看吧 哈哈哈O(∩_∩)O哈哈~ 最近看见别人弄得自动部署 自己也是手痒痒 也想弄一个 所以就弄了一个 windows的 我用的是https的  在网上看了很多都是 s ...

  9. post文件下载

    this.$http({ method: 'post', url: '/file/download', responseType: 'blob', data: JSON.stringify(this. ...

  10. java maven web 项目启动之后,访问所有页面为空白,不是404!!!

    自己解决了大半天,后面通过解决spring单元测试的时候,发现单元测试可以用了,项目启动也可以访问页面了,具体原因不太清楚 可能原因: (1)pom.xml 依赖有重复的地方 (2)不排除与公司内网有 ...