Golang标准库——io-结构
结构
LimitedReader
定义
限制从Reader中读取的字节数。
type LimitedReader struct {
R Reader // underlying reader
N int64 // max bytes remaining
}
方法
//Limited
func (l *LimitedReader) Read(p []byte) (n int, err error) {
//已经读完了返回EOF
if l.N <= 0 {
return 0, EOF
}
//限制读取的长度
if int64(len(p)) > l.N {
p = p[0:l.N]
}
//直接调用Reader的Read
n, err = l.R.Read(p)
//更新N,保证一个LimitReader限制字节数
l.N -= int64(n)
return
}
SectionReader
定义
实现了对底层满足ReadAt接口的输入流某个片段的Read、ReadAt、Seek方法.
type SectionReader struct {
r ReaderAt
base int64 //读取的起始偏移
off int64 //读取时的指针
limit int64 //最终位置
}
方法
//读
func (s *SectionReader) Read(p []byte) (n int, err error) {
//超过limit返回EOF
if s.off >= s.limit {
return 0, EOF
}
//计算最大可以读取的长度,进而修改slice
if max := s.limit - s.off; int64(len(p)) > max {
p = p[0:max]
}
//从off开始读取len(p)个字节
n, err = s.r.ReadAt(p, s.off)
s.off += int64(n)
return
}
//跳转后的偏移能大于limit吗??
//Seeker
//返回跳转后与起始位置的偏移
func (s *SectionReader) Seek(offset int64, whence int) (int64, error) {
switch whence {
default:
return 0, errWhence
case SeekStart: //SeekStart = 0 // 相对起始位置跳转
offset += s.base
case SeekCurrent: //SeekCurrent = 1 // 相对当前位置跳转
offset += s.off
case SeekEnd: //SeekEnd = 2 // 相对最后位置跳转
offset += s.limit
}
//跳转后偏移必须大于起始位置
if offset < s.base {
return 0, errOffset
}
s.off = offset
return offset - s.base, nil
}
//off为相对base偏移量
func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err error) {
//不能大于Size()
if off < 0 || off >= s.limit-s.base {
return 0, EOF
}
//设置ReadAt的初始位置,该off不能影响SectionReader.off
off += s.base
//计算可以读取的长度
if max := s.limit - off; int64(len(p)) > max {
p = p[0:max]
n, err = s.r.ReadAt(p, off)
//此时len(p)>max,因此需要设置文件结束的err
if err == nil {
err = EOF
}
return n, err
}
//可以直接读取
return s.r.ReadAt(p, off)
}
func (s *SectionReader) Size() int64 { return s.limit - s.base }
teeReader
定义
私有结构,需要通过TeeReader函数创建一个teeReader,使读取r的数据之前均写入到w中
type teeReader struct {
r Reader
w Writer
}
方法
func (t *teeReader) Read(p []byte) (n int, err error) {
//从r中读数据
n, err = t.r.Read(p)
if n > 0 {
//想w写入数据
if n, err := t.w.Write(p[:n]); err != nil {
return n, err
}
}
return
}
multiReader
定义
通过MultiReader创建,从多个Reader中连续读取
type multiReader struct {
readers []Reader
}
方法
//实现Reader接口
//从readers中按顺序读取数据
func (mr *multiReader) Read(p []byte) (n int, err error) {
for len(mr.readers) > 0 {
// Optimization to flatten nested multiReaders (Issue 13558).
//嵌套multiReader
if len(mr.readers) == 1 {
if r, ok := mr.readers[0].(*multiReader); ok {
mr.readers = r.readers
continue
}
}
n, err = mr.readers[0].Read(p)
//判断当前Reader是否读完
if err == EOF {
//释放对已读完的Reader的引用
mr.readers[0] = eofReader{} // permit earlier GC
//剔除第一个元素
mr.readers = mr.readers[1:]
}
//如果readers还有则不能返回EOF
if n > 0 || err != EOF {
if err == EOF && len(mr.readers) > 0 {
// Don't return EOF yet. More readers remain.
err = nil
}
return
}
}
return 0, EOF
}
multiWriter
定义
通过MultiWriter创建,每次写入数据会同时写入到这一组Writer
type multiWriter struct {
writers []Writer
}
方法
func (t *multiWriter) Write(p []byte) (n int, err error) {
//循环写入
for _, w := range t.writers {
n, err = w.Write(p)
//某个报错则返回
if err != nil {
return
}
//必须将p都写入
if n != len(p) {
err = ErrShortWrite
return
}
}
return len(p), nil
}
//写字符串
func (t *multiWriter) WriteString(s string) (n int, err error) {
var p []byte // lazily initialized if/when needed
for _, w := range t.writers {
//判断是否实现了stringWriter接口
if sw, ok := w.(stringWriter); ok {
n, err = sw.WriteString(s)
} else {
//将string转为slice
if p == nil {
p = []byte(s)
}
//调用Write
n, err = w.Write(p)
}
if err != nil {
return
}
//所有Writer必须都写完
if n != len(s) {
err = ErrShortWrite
return
}
}
return len(s), nil
}
pipe
定义
PipeReader和PipeWriter的底层实现
type pipe struct {
rl sync.Mutex // gates readers one at a time
wl sync.Mutex // gates writers one at a time
l sync.Mutex // protects remaining fields
data []byte // data remaining in pending write
rwait sync.Cond // waiting reader
wwait sync.Cond // waiting writer
rerr error // if reader closed, error to give writes
werr error // if writer closed, error to give reads
}
方法
func (p *pipe) read(b []byte) (n int, err error) {
// One reader at a time.
//上Reader的锁
p.rl.Lock()
defer p.rl.Unlock()
//锁其他字段
p.l.Lock()
defer p.l.Unlock()
//死循环直到有数据可读了
for {
//reader关闭了
if p.rerr != nil {
return 0, ErrClosedPipe
}
//可以读数据了
if p.data != nil {
break
}
//writer关闭了
if p.werr != nil {
return 0, p.werr
}
//阻塞读
p.rwait.Wait()
}
//读数据
n = copy(b, p.data)
p.data = p.data[n:]
//pipe中数据读完了则可以notify Writer
if len(p.data) == 0 {
p.data = nil
p.wwait.Signal()
}
return
}
func (p *pipe) write(b []byte) (n int, err error) {
// pipe uses nil to mean not available
if b == nil {
b = zero[:]
}
// One writer at a time.
p.wl.Lock()
defer p.wl.Unlock()
p.l.Lock()
defer p.l.Unlock()
//Writer关闭抛异常
if p.werr != nil {
err = ErrClosedPipe
return
}
//写入数据
p.data = b
//notify Reader
p.rwait.Signal()
//阻塞,直到Reader读完
for {
if p.data == nil {
break
}
if p.rerr != nil {
err = p.rerr
break
}
if p.werr != nil {
err = ErrClosedPipe
break
}
p.wwait.Wait()
}
n = len(b) - len(p.data)
p.data = nil // in case of rerr or werr
return
}
PipeReader/PipeWriter
定义
通过Pipe()函数创建(*PipeReader, *PipeWriter)
type PipeReader struct {
p *pipe
}
type PipeWriter struct {
p *pipe
}
方法
- Write,调用pipe.write
- Read,调用pipe.read
Golang标准库——io-结构的更多相关文章
- Golang 标准库log的实现
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://gotaly.blog.51cto.com/8861157/1406905 前 ...
- golang 标准库间依赖的可视化展示
简介 国庆看完 << Go 语言圣经 >>,总想做点什么,来加深下印象.以可视化的方式展示 golang 标准库之间的依赖,可能是一个比较好的切入点.做之前,简单搜了下相关的内 ...
- Golang 标准库提供的Log(一)
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://gotaly.blog.51cto.com/8861157/1405754 G ...
- golang标准库分析之net/rpc
net/rpc是golang提供的一个实现rpc的标准库.
- C 标准库IO缓冲区和内核缓冲区的区别
1.C标准库的I/O缓冲区 UNIX的传统 是Everything is a file,键盘.显示器.串口.磁盘等设备在/dev 目录下都有一个特殊的设备文件与之对应,这些设备文件也 ...
- golang 标准库
前言 不做文字搬运工,多做思路整理 就是为了能速览标准库,只整理我自己看过的...... 最好能看看英文的 标准库 fmt strconv string 跳转 golang知识库总结
- golang中的标准库IO操作
参考链接 输入输出的底层原理 终端其实是一个文件,相关实例如下: os.Stdin:标准输入的文件实例,类型为*File os.Stdout:标准输出的文件实例,类型为*File os.Stderr: ...
- 使用C++/C qsort 标准库对结构体进行快速排序
C++标准快速排序库qsort进行结构体快速排序 代码如下 #include <stdio.h> #include <stdlib.h> typedef struct { in ...
- golang标准库 context的使用
本文索引 问题引入 context包简介 示例 问题引入 goroutine为我们提供了轻量级的并发实现,作为golang最大的亮点之一更是备受推崇. goroutine的简单固然有利于我们的开发,但 ...
- python 标准库 —— io(StringIO)
0. io流(io stream) 流是一种抽象概念,它代表了数据的无结构化传递.按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列.从流中取得数据的操作称为提取操作,而向流中添加数据的操作 ...
随机推荐
- DevExpress数据源 BindingList<FilesList> 与BindSource 使用区别
这两个都能实现对接girdcontrol.datasource . 我只是说我自己用的时候的差异 bingsource bs 添加了对象 之后成为一个对象集合 你是无法用foreach (var ...
- Luogu3119 草鉴定-Tarjan+Topsort
Solution 简单的$Tarjan$题. 有大佬现成博客 就不写了 → 传送门 Code #include<cstdio> #include<cstring> #inclu ...
- HDU 3594.Cactus 仙人掌图
Cactus Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- maven pom.xml文件 仓库搜索服务
POM(Project Object Model),即项目对象模型,是 Maven 工程的基本工作单元,是一个 XML 文件,包含了项目的基本信息,用于描述项目如何构建.声明项目依赖 等等 Maven ...
- js判断手机系统(Android或IOS),跳转相应下载地址
<script type="text/javascript"> $(document).ready(function(e) { var u = navigator.us ...
- python_day12_html
目录: 简单web的服务器代码 html简介 html常用标签 一.简单web的服务器代码 1.简单python服务器代码: import socket def main(): sock = sock ...
- Activity 重载方法 onStart和onResume、onPause和onStop的区别
Activity 重载方法 onStart和onResume.onPause和onStop的区别 首先了解Activity的四种状态 Running状态:一个新的Activity启动入栈后,它在屏幕最 ...
- 手动上传图片到nginx下可访问,程序上传后访问图片报403
1. 首先查看文件权限 2. 初步确定是服务器权限问题 2.1 解决方案一:更改文件权限 2.2 解决方案二:修改nginx运行用户 1. 首先查看文件权限 #指令如下 ls -l 2. 初步确定是服 ...
- 程序中使用now()函数对性能的影响
这两天从某平台的慢查询日志中发现了一些很简单的,原本执行时间在0.01-0.03s的SQL,慢查询日志中记录的执行时间在2s左右. 排查后发现,表设计及索引建设均没有什么问题.但是SQL语句中使用了n ...
- windows安装mongodb及相关命令
- 安装 解压: mongodb-win32-x86_64-2008plus-ssl-3.6.4.7z 将文件夹改名为mongodb 移动文件到指定目录下,如: C:\python\soft ...