golang IO streaming
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方法的读取机制
- 尽可能读取len(p)字节到p
- 调用Read()后,n可能比len(p)小
- 如果出现错误,read()仍可能返回缓冲区p中的n个字节。例如,读取突然关闭的TCP套接字。根据您的使用,您可以选择将字节保持在p中或重试。
- 当Read()读尽数据后,可能返回非零的n和err=io.EOF。甚至出现返回非零n和err=nil的情况,但是接下来的Read()方法调用一定返回n=0, err=io.EOF
- 当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的更多相关文章
- 简析 Golang IO 包
简析 Golang IO 包 io 包提供了 I/O 原语(primitives)的基本接口.io 包中定义了四个最基本接口 Reader.Writer.Closer.Seeker 用于表示二进制流的 ...
- golang io中io.go解读
目录 1. 整体大纲 2. 接口 读 写 关闭 寻址 3. 函数 读 写 复制 4. 结构体 SectionReader LimitedReader teeReader 5. 备注 根据golang ...
- Golang IO包的妙用
Golang 标准库对 IO 的抽象非常精巧,各个组件可以随意组合,可以作为接口设计的典范.这篇文章结合一个实际的例子来和大家分享一下. 背景 以一个RPC的协议包来说,每个包有如下结构 type P ...
- golang io需要牢记的几个点
对于Reader比较麻烦需要记住以下: When Read encounters an error or end-of-file condition after successfully readin ...
- golang io.ReadFull
buf := make([]byte, 10, 10) file, _ := os.Open("./data.txt") n, err := io.ReadFull(file, b ...
- 【Linux开发】IO streaming DMA buffer importing
http://linuxtv.org/downloads/v4l-dvb-apis/dmabuf.html I/O流 (DMA缓存引用) 这是一个实验性接口,将来可能发生改变 DMABUF框架提供了在 ...
- golang io操作之写篇
/** * @author livalon * @data 2018/9/4 15:11 */ package main import ( "os" "fmt" ...
- 实现golang io.Writer支持按照天为单位分割日志
golang中的日志不支持按照天分割,很多开源的日志包都是只支持按照文件大小分割日志,不太利于生产环境中的使用.因此我实现了timewriter,支持: 实现按照天为单位分割日志,可以完美支持gola ...
- golang IO 流抽象与应用
https://blog.csdn.net/pmlpml/article/details/82930191
随机推荐
- Android自动化之Monkey测试(二)
本文主要从以下方面进行分享. 一.查看应用包名二.Monkey启动三.Monkey停止四.Monkey命令五.日志分析 一.查看应用包名 大多数时候,我们都是对特定的应用进行monkey测试,因此需要 ...
- db2数据库备份及恢复
导出 1. 连接数据库,命令如下: db2 connect to db_name user user_name using password db_name 是指数据库的名字, user_name 是 ...
- git服务搭建以及本地连接
服务器系统:centos6.5 本地系统:Mac 10.11 注意事项:本地git和服务器版本最好一样,centos上面的yum install git版本是1.7的,需要手动在下载,并手动编译 下载 ...
- Lab keepalived
[root@node1 keepalived]#cat keepalived.conf ! Configuration File for keepalived global_defs { notifi ...
- 修改mysql登录密码
通过cmd 登录进mysql系统后,输入 : set password for root@localhost = password('admin'); 其中admin 为新密码: 导入外部数据库 ...
- windows和ubuntu下git commit提交后如何保存和退出,回到命令行
问题一: windows下git commit后会进入vim界面,不知道怎么操作 解决办法: 1.输入小写字母i,此时进入编辑模式,可以输入你想输入的内容 2.按下esc键,此时退出编辑模式,输入英文 ...
- github install
1.安装git依赖包 yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc perl-ExtUti ...
- html、css基础整理
1.块元素与行内元素之间的转换: HTML可以将元素分类方式分为行内元素.块状元素和行内块状元素三种.这三者是可以互相转换的,使用display属性能够将三者任意转换: (1)display:inli ...
- python猜数字GUI版本V0.1
非常简单的GUI版猜数字游戏,后面有时间好好研究下 # -*- coding: utf-8 -*-"""Created on Mon Jan 28 16:30:17 20 ...
- 利用UiWatchers 监听解决安卓自动化各种自动化各种非期待弹窗,弹层,升级,广告,对话框,来电等问题
app自动化时,各种不期待的弹层弹窗,升级广告等时有飞出,由于弹窗具有不定时,不定页面等很多不确定性.有的弹窗很不友好,不×掉,很难进行下一步操作,造成 测试用例失败.而判断是否有弹窗,弹层很麻烦.研 ...