Menu

  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay
  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay

Go语言IO编程

1
Feb
2017

Go语言IO编程

By Alex
/ in Go
/ tags IO编程, 文本处理
0 Comments
相关包
io

该包为IO操作原语提供了基本的接口,它包装了IO操作原语的实现(例如os包中的类型)。除非特别说明,调用者不能假设接口中的方法可以被并行调用。

常量变量
Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const (
        SeekStart   = 0 // 相对于文件的起始位置进行Seek
        SeekCurrent = 1 // 相对于当前读取位置进行Seek
        SeekEnd     = 2 // 相对于尾部进行Seek
)
 
// 错误定义
// 由Read函数返回,表示没有更多可读的数据。用于优雅的结束文件读取(读到尾部了)
var EOF = errors.New("EOF")
// 在关闭的管道上进行读写
var ErrClosedPipe = errors.New("io: read/write on closed pipe")
var ErrNoProgress = errors.New("multiple Read calls return no data or error")、
// 当提供的缓冲区不够存放读取到的数据时
var ErrShortBuffer = errors.New("short buffer")
// 当写操作所要求的字节数不足时
var ErrShortWrite = errors.New("short write")
// 在读取固定长度的块或者数据结构时,没有到预期的结尾位置即发生EOF
var ErrUnexpectedEOF = errors.New("unexpected EOF")
函数类型
函数 说明
Copy

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

从src读取数据并写入到dst,直到src的EOF。返回写入dst的字节数,操作成功则err为nil

实现方式:如果src实现了WriterTo接口,则调用src.WriteTo(dst);如果dst实现了ReaderFrom接口,则调用dst.ReadFrom(src)

示例代码:

Go
1
2
3
4
5
sr := strings.NewReader("Read after me, please!\n")
n, err := io.Copy(os.Stderr, sr)
if err == nil {
    fmt.Printf("%v bytes read.\n", n)
}
CopyBuffer

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

和上面类似,只是拷贝时使用给定的缓冲区。如果buf为nil则自动创建一个缓冲区,如果buf长度为0则panic

CopyN 

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

拷贝N个字节,或知道遇到错误。返回拷贝的字节数和遇到的错误

ReadAtLeast 

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

从r读取至少min字节到buf,返回读取的字节数,如果没有读取到至少min字节数,则返回错误:

  1. 如果一个字节也没有读到,返回EOF
  2. 如果读到一部分字节,返回ErrUnexpectedEOF

示例:

Go
1
2
3
4
r := bytes.NewReader([]byte{0, 1, 2, 3, 4, 5, 7, 8, 9})
buf := make([]byte, 5)
io.ReadAtLeast(r, buf, 3)
fmt.Printf("%v", buf)  // [0 1 2 3 4] 读满了切片容量 
ReadFull

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

读取r的全部内容到buf中,返回实际读取的字节数,如果:

  1. 如果一个字节也没有读到,返回EOF
  2. 如果读到一部分字节(而非r的全部字节),返回ErrUnexpectedEOF
 WriteString

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

将字符串s的内容写入到w中,如果w实现了WriteString方法则直接调用之,否则调用其Write一次

ByteReader
Go
1
2
3
type ByteReader interface {
    ReadByte() (byte, error)
}
ByteScanner 
Go
1
2
3
4
5
type ByteScanner interface {
    ByteReader
    // 导致下一次ReadByte返回和上一次ReadByte一样的内容
    UnreadByte() error
} 
ByteWriter
Go
1
2
3
type ByteWriter interface {
    WriteByte(c byte) error
} 
Closer 
Go
1
2
3
4
type Closer interface {
    // 此接口包装基本的Close方法
    Close() error
}
LimitedReader 
Go
1
2
3
4
type LimitedReader struct {
    R Reader // 此结构使用的Reader
    N int64  // 最大读取字节数。每次调用R后等会更新N,来反应还可以读取多少字节
}

该结构上定义的方法:

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

Pipe

func Pipe() (*PipeReader, *PipeWriter)

创建一个同步的、内存中的管道,用于连接Reader和Writer

每个PipeWriter.Write调用都会阻塞,直到一个或多个PipeReader.Read了其写入的全部数据,没有内部缓冲区

并行调用Read/Write是安全的

PipeReader
Go
1
type PipeReader struct {}

 表示管道能读的那一端。该结构上定义以下方法:

Go
1
2
3
4
5
6
// 关闭管道的读端,后续写端的写操作会返回ErrClosedPipe
func (r *PipeReader) Close() error
// 关闭管道的读端,后续写端的写操作会返回该方法提供的err
func (r *PipeReader) CloseWithError(err error) error
// 读取数据
func (r *PipeReader) Read(data []byte) (n int, err error)
PipeWriter
Go
1
type PipeWriter struct {}

表示管道能写的那一端。 该结构上定义以下方法:

Go
1
2
3
func (w *PipeWriter) Close() error
func (w *PipeWriter) CloseWithError(err error) error
func (w *PipeWriter) Write(data []byte) (n int, err error) 
MultiReader

func MultiReader(readers ...Reader) Reader

串联多个Reader,示例:

Go
1
2
3
4
5
6
r1 := strings.NewReader("Hello")            
r2 := strings.NewReader(" World")            
rm := io.MultiReader(r1, r2)                
buf := make([]byte, 20)                      
io.ReadFull(rm, buf)                        
fmt.Printf("%v", string(buf)) // Hello World
TeeReader

 

func TeeReader(r Reader, w Writer) Reader

返回一个Reader,它会把所有读取到的东西写入到一个Writer中,没有内部缓冲

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

包装ReadAt函数,支持从指定的偏移量开始读取。它从底层数据源偏移量off处开始,读取最多len(p)字节到缓冲区p中

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

 包装ReadFrom函数,它从r读取数据,直到EOF或者错误

NewSectionReader

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

返回一个Reader,它从off读取r,读取最多n字节

SectionReader
Go
1
2
3
4
5
6
7
8
9
10
iotype SectionReader struct {
}
// 读取
func (s *SectionReader) Read(p []byte) (n int, err error)
// 从指定位置开始读取
func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err error)
// Seek到指定位置
func (s *SectionReader) Seek(offset int64, whence int) (int64, error)
返回节段中包含的字节数
func (s *SectionReader) Size() int64

 示例:

Go
1
2
3
4
5
6
7
8
9
r := bytes.NewReader([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
s := io.NewSectionReader(r, 2, 3)
buf := make([]byte, 10)
s.Read(buf)
fmt.Printf("%v", buf) // [2 3 4 0 0 0 0 0 0 0] 最多读取3字节
 
s = io.NewSectionReader(r, 0, 10)
s.ReadAt(buf, 5)
fmt.Printf("%v", buf) // [5 6 7 8 9 0 0 0 0 0] 
 RuneReader
Go
1
2
3
type RuneReader interface {
    ReadRune() (r rune, size int, err error)
}

包装RuneReader函数。ReadRune读取单个UTF-8字符,返回一个rune及其长度 

bufio

该包实现带缓冲的IO功能。执行很多碎小的写操作会影响性能,因为每次写操作都对应了系统调用,过多的系统调用会加重CPU负担。类似磁盘这样的设备,处理块对齐的数据时性能更好,因此有必要为IO提供缓冲功能。

缓冲写

简单的示例: 

Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 实现一个仿冒Writer,它能够打印写出的字节数量
type Writer int
 
func (*Writer) Write(p []byte) (n int, err error) {
    fmt.Printf("Bytes write: %v\n", len(p))
    return len(p), nil
}
func main() {
    w := new(Writer)
    w.Write([]byte{1}) // 一字节无缓冲写出
    w.Write([]byte{2})
 
    // 创建带缓冲的Writer,缓冲区大小5字节
    bw := bufio.NewWriterSize(w, 5)
    bw.Write([]byte{1, 2, 3}) // 不会写出,因为缓冲区没有满
    bw.Write([]byte{4, 5, 6}) // 写出,输出5
    fmt.Printf("Available size of buffer: %v", bw.Available())
    bw.Flush() // 写出,输出1
}
缓冲读 
Go
1
2
3
4
5
6
7
8
9
10
11
12
r := strings.NewReader("既然选择了远方,就应该风雨兼程")
br := bufio.NewReaderSize(r, 18)
rune, size, err := br.ReadRune()
if err == nil {
    fmt.Printf("Character: %c, Size: %v\n", rune, size) // Character: 既, Size: 3
}
buf := make([]byte, 18)
br.Read(buf)
fmt.Printf("String: %v", string(buf)) // String: 然选择了远
br.Discard(6)
rune, _, _ = br.ReadRune()
fmt.Printf("%c", rune) // 就
缓冲扫描 
Go
1
2
3
4
5
6
7
8
9
10
func main() {
    // 扫描器可以方便进行扫描,例如逐行读取、逐字符读取
    bs := bufio.NewScanner(strings.NewReader("既然选择了远方,就应该风雨兼程"))
    // 每读取一个字符即停止
    bs.Split(bufio.ScanRunes)
    for bs.Scan() {
        // 以字符串形式返回读取到的内容
        fmt.Print(bs.Text())
    }
}
ioutil

包含一些工具函数

Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 读取全部内容
bytes, err := ioutil.ReadAll(strings.NewReader("Hello darkness my old friend"))
if err == nil {
    fmt.Printf("%c", bytes)
}
 
// 读取目录的全部条目
infos, err := ioutil.ReadDir("/etc/mysql")
for _, info := range infos {
    // 打印目录中的内容
    fmt.Println(info.Name())
}
 
// 读取文件的内容并返回
const FNAME = "/etc/mysql/my.cnf"
content, _ := ioutil.ReadFile(FNAME)
// 写入文件内容
ioutil.WriteFile(FNAME, content, 0777)
 
// 创建临时文件和目录
dirName, _ := ioutil.TempDir("", "go")
fmt.Println(dirName) // 输出目录/tmp/go154074736,注意随机后缀
fmt

该包提供类似C语言风格的printf、scanf

格式化动词
动词 说明
%v 值的默认形式
%#v 值的Go语法展现形式
%T 值类型的Go语法展现形式
%t true或false
%% 转义%且不消耗参数
整数格式化
%b 二进制整数
%c Unicode代码点对应的字符
%d 十进制
%o 八进制
%q 用引号包围的字符串形式,转义已经处理好
%x 十六进制a-f
%X 十六进制A-F
%U Unicode格式
浮点数和复数
%e 科学计数法,使用e
%E 科学计数法,使用E
%f  %F 小数格式,示例: fmt.Printf("%f",12.22) // 12.220000 
%g  %G 对于大的指数使用%e %E,否则使用%f
字符串和字节切片
%s 未解释的原始字节
%q 引号包围的已经转义的字符串
%x  %X 十六进制表示,每个字节2字符
指针
%p 0x开头的十六进制
复合类型 
类型 格式化为
结构 {field0 field1 ...}
数组和切片 [elem0 elem1 ...]
映射 map[key1:value1 key2:value2]
上述类型的指针 &{}, &[], &map[]
指定宽度
示例 说明
%f 默认宽度和精度
%9f 宽度为9,默认精度
%.2f 默认宽度,精度为2
%9.2f 宽度为9,精度为2
%9.f 宽度为9,精度为0
文件处理
打开文件
Go
1
2
3
4
5
// 打开并得到os.File对象
f, err := os.Open("/etc/rc.local")
 
// 关闭文件
defer f.Close()
读取文件
读取到缓冲区
Go
1
2
3
4
# 读取最多5字节到缓冲
b1 := make([]byte, 5)
# 返回实际读取的字节数
n1, err := f.Read(b1)
随机访问 
Go
1
2
3
4
5
6
7
// 寻道到第6字节处,第二参数:0相对于文件头,1 相对于当前位置,2相对于文件尾
o2, err := f.Seek(6, 0)
b2 := make([]byte, 2)
n2, err := f.Read(b2)
 
// Rewind
f.Seek(0, 0)
缓冲读
Go
1
2
3
r4 := bufio.NewReader(f)
// 向前偷窥
b4, err := r4.Peek(5)

 

← Blender知识集锦
Go语言网络编程 →

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Related Posts

  • Linux IO编程
  • 使用Python进行文本处理
  • 使用C语言进行文本处理
  • Istio Mixer与Envoy的交互机制解读
  • Gorilla学习笔记

Recent Posts

  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
  • A Comprehensive Study of Kotlin for Java Developers
  • 背诵营笔记
  • 利用LangChain和语言模型交互
  • 享学营笔记
ABOUT ME

汪震 | Alex Wong

江苏淮安人,现居北京。目前供职于腾讯云,专注容器方向。

GitHub:gmemcc

Git:git.gmem.cc

Email:gmemjunk@gmem.cc@me.com

ABOUT GMEM

绿色记忆是我的个人网站,域名gmem.cc中G是Green的简写,MEM是Memory的简写,CC则是我的小天使彩彩名字的简写。

我在这里记录自己的工作与生活,同时和大家分享一些编程方面的知识。

GMEM HISTORY
v2.00:微风
v1.03:单车旅行
v1.02:夏日版
v1.01:未完成
v0.10:彩虹天堂
v0.01:阳光海岸
MIRROR INFO
Meta
  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org
Recent Posts
  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
    In this blog post, I will walk ...
  • A Comprehensive Study of Kotlin for Java Developers
    Introduction Purpose of the Study Understanding the Mo ...
  • 背诵营笔记
    Day 1 Find Your Greatness 原文 Greatness. It’s just ...
  • 利用LangChain和语言模型交互
    LangChain是什么 从名字上可以看出来,LangChain可以用来构建自然语言处理能力的链条。它是一个库 ...
  • 享学营笔记
    Unit 1 At home Lesson 1 In the ...
  • K8S集群跨云迁移
    要将K8S集群从一个云服务商迁移到另外一个,需要解决以下问题: 各种K8S资源的迁移 工作负载所挂载的数 ...
  • Terraform快速参考
    简介 Terraform用于实现基础设施即代码(infrastructure as code)—— 通过代码( ...
  • 草缸2021
    经过四个多月的努力,我的小小荷兰景到达极致了状态。

  • 编写Kubernetes风格的APIServer
    背景 前段时间接到一个需求做一个工具,工具将在K8S中运行。需求很适合用控制器模式实现,很自然的就基于kube ...
  • 记录一次KeyDB缓慢的定位过程
    环境说明 运行环境 这个问题出现在一套搭建在虚拟机上的Kubernetes 1.18集群上。集群有三个节点: ...
  • eBPF学习笔记
    简介 BPF,即Berkeley Packet Filter,是一个古老的网络封包过滤机制。它允许从用户空间注 ...
  • IPVS模式下ClusterIP泄露宿主机端口的问题
    问题 在一个启用了IPVS模式kube-proxy的K8S集群中,运行着一个Docker Registry服务 ...
  • 念爷爷
      今天是爷爷的头七,十二月七日、阴历十月廿三中午,老人家与世长辞。   九月初,回家看望刚动完手术的爸爸,发

  • 6 杨梅坑

  • liuhuashan
    深圳人才公园的网红景点 —— 流花山

  • 1 2020年10月拈花湾

  • 内核缺陷触发的NodePort服务63秒延迟问题
    现象 我们有一个新创建的TKE 1.3.0集群,使用基于Galaxy + Flannel(VXLAN模式)的容 ...
  • Galaxy学习笔记
    简介 Galaxy是TKEStack的一个网络组件,支持为TKE集群提供Overlay/Underlay容器网 ...
TOPLINKS
  • Zitahli's blue 91 people like this
  • 梦中的婚礼 64 people like this
  • 汪静好 61 people like this
  • 那年我一岁 36 people like this
  • 为了爱 28 people like this
  • 小绿彩 26 people like this
  • 彩虹姐姐的笑脸 24 people like this
  • 杨梅坑 6 people like this
  • 亚龙湾之旅 1 people like this
  • 汪昌博 people like this
  • 2013年11月香山 10 people like this
  • 2013年7月秦皇岛 6 people like this
  • 2013年6月蓟县盘山 5 people like this
  • 2013年2月梅花山 2 people like this
  • 2013年淮阴自贡迎春灯会 3 people like this
  • 2012年镇江金山游 1 people like this
  • 2012年徽杭古道 9 people like this
  • 2011年清明节后扬州行 1 people like this
  • 2008年十一云龙公园 5 people like this
  • 2008年之秋忆 7 people like this
  • 老照片 13 people like this
  • 火一样的六月 16 people like this
  • 发黄的相片 3 people like this
  • Cesium学习笔记 90 people like this
  • IntelliJ IDEA知识集锦 59 people like this
  • 基于Kurento搭建WebRTC服务器 38 people like this
  • Bazel学习笔记 37 people like this
  • PhoneGap学习笔记 32 people like this
  • NaCl学习笔记 32 people like this
  • 使用Oracle Java Mission Control监控JVM运行状态 29 people like this
  • Ceph学习笔记 27 people like this
  • 基于Calico的CNI 27 people like this
Tag Cloud
ActiveMQ AspectJ CDT Ceph Chrome CNI Command Cordova Coroutine CXF Cygwin DNS Docker eBPF Eclipse ExtJS F7 FAQ Groovy Hibernate HTTP IntelliJ IO编程 IPVS JacksonJSON JMS JSON JVM K8S kernel LB libvirt Linux知识 Linux编程 LOG Maven MinGW Mock Monitoring Multimedia MVC MySQL netfs Netty Nginx NIO Node.js NoSQL Oracle PDT PHP Redis RPC Scheduler ServiceMesh SNMP Spring SSL svn Tomcat TSDB Ubuntu WebGL WebRTC WebService WebSocket wxWidgets XDebug XML XPath XRM ZooKeeper 亚龙湾 单元测试 学习笔记 实时处理 并发编程 彩姐 性能剖析 性能调优 文本处理 新特性 架构模式 系统编程 网络编程 视频监控 设计模式 远程调试 配置文件 齐塔莉
Recent Comments
  • qg on Istio中的透明代理问题
  • heao on 基于本地gRPC的Go插件系统
  • 黄豆豆 on Ginkgo学习笔记
  • cloud on OpenStack学习笔记
  • 5dragoncon on Cilium学习笔记
  • Archeb on 重温iptables
  • C/C++编程:WebSocketpp(Linux + Clion + boostAsio) – 源码巴士 on 基于C/C++的WebSocket库
  • jerbin on eBPF学习笔记
  • point on Istio中的透明代理问题
  • G on Istio中的透明代理问题
  • 绿色记忆:Go语言单元测试和仿冒 on Ginkgo学习笔记
  • point on Istio中的透明代理问题
  • 【Maven】maven插件开发实战 – IT汇 on Maven插件开发
  • chenlx on eBPF学习笔记
  • Alex on eBPF学习笔记
  • CFC4N on eBPF学习笔记
  • 李运田 on 念爷爷
  • yongman on 记录一次KeyDB缓慢的定位过程
  • Alex on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • haolipeng on 基于本地gRPC的Go插件系统
  • 吴杰 on 基于C/C++的WebSocket库
©2005-2025 Gmem.cc | Powered by WordPress | 京ICP备18007345号-2