Go标准库-带缓冲的IO(bufio)

概述
bufio模块通过对io模块的封装,提供了数据缓冲功能,能够一定程度减少大块数据读写带来的开销。

实际上在bufio各个组件内部都维护了一个缓冲区,数据读写操作都直接通过缓存区进行。当发起一次读写操作时,会首先尝试从缓冲区获取数据;只有当缓冲区没有数据时,才会从数据源获取数据更新缓冲。

Reader
可以通过NewReader函数创建bufio.Reader对象,函数接收一个io.Reader作为参数;也就是说,bufio.Reader不能直接使用,需要绑定到某个io.Reader上。函数声明如下:

func NewReader(rd io.Reader) *Reader

func NewReaderSize(rd io.Reader, size int) *Reader // 可以配置缓冲区的大小

相较于io.Reader,bufio.Reader提供了很多实用的方法,能够更有效的对数据进行读取。首先是几个基础方法,它们能够对Reader进行细粒度的操作:

Read,读取n个byte数据
Discard,丢弃接下来n个byte数据
Peek,获取当前缓冲区内接下来的n个byte,但是不移动指针
Reset,清空整个缓冲区
具体的方法声明如下:

func (b *Reader) Read(p []byte) (n int, err error)

func (b *Reader) Discard(n int) (discarded int, err error)

func (b *Reader) Peek(n int) ([]byte, error)

func (b *Reader) Reset(r io.Reader)

除了上面的基础操作之外,bufio.Reader还提供了多个更高抽象层次的方法对数据进行简单的结构化读取。主要包括如下几个方法:

ReadByte,读取一个byte
ReadRune,读取一个utf-8字符
ReadLine,读取一行数据,由’\n’分隔
ReadBytes,读取一个byte列表
ReadString,读取一个字符串
其中前三个函数都没有参数,会从缓冲区读取一个满足需求的数据。后面两个函数接收一个参数delim,用于做数据拆分,持续读取数据直到当前字节的值等于delim,然后返回这些数据;实际上这两个函数功能相同,只是在函数返回值的类型上有所区别。具体的方法声明如下:

func (b *Reader) ReadByte() (byte, error)

func (b *Reader) ReadRune() (r rune, size int, err error)

func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)

func (b *Reader) ReadBytes(delim byte) ([]byte, error)

func (b *Reader) ReadString(delim byte) (string, error)

下面是一个简单的示例,使用ReadString方法获取用‘ ’分隔的字符串。

package main

import (
"bufio"
"fmt"
"strings"
)

func main() {
r := strings.NewReader("hello world !")
reader := bufio.NewReader(r)

  for {
  str, err := reader.ReadString(byte(‘ ‘))
  fmt.Println(str)
  if err != nil {
  return
  }
  }
  }

Scanner
实际使用中,更推荐使用Scanner对数据进行读取,而非直接使用Reader类。Scanner可以通过splitFunc将输入数据拆分为多个token,然后依次进行读取。

和Reader类似,Scanner需要绑定到某个io.Reader上,通过NewScannner进行创建,函数声明如下:

func NewScanner(r io.Reader) *Scanner

在使用之前还需要设置splitFunc(默认为ScanLines),splitFunc用于将输入数据拆分为多个token。bufio模块提供了几个默认splitFunc,能够满足大部分场景的需求,包括:

ScanBytes,按照byte进行拆分
ScanLines,按照行(“\n”)进行拆分
ScanRunes,按照utf-8字符进行拆分
ScanWords,按照单词(” “)进行拆分
通过Scanner的Split方法,可以为Scanner指定splitFunc。使用方法如下:

  scanner := bufio.NewScanner(os.StdIn)

  scanner.split(bufio.ScanWords)

除此了默认的splitFunc之外,也可以定义自己的splitFunc,函数需要满足如下声明:

  type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)

函数接收两个参数,第一个参数是输入数据,第二个参数是一个标识位,用于标识当前数据是否为结束。函数返回三个参数,第一个是本次split操作的指针偏移;第二个是当前读取到的token;第三个是返回的错误信息。

在完成了Scanner初始化之后,通过Scan方法可以在输入中向前读取一个token,读取成功返回True;使用Text和Bytes方法获取这个token,Text返回一个字符串,Bytes返回字节数组。方法声明如下:

  func (s *Scanner) Scan() bool

  func (s *Scanner) Text() string

  func (s *Scanner) Text() []byte

下面的示例使用Scanner对上面的示例进行了重现,可以看到和Reader相比,Scanner的使用更加便捷。

  package main

  import (
  "bufio"
  "strings"
  "fmt"
  )

  func main() {

  scanner := bufio.NewScanner(strings.NewReader("hello world !"))

  scanner.Split(bufio.ScanWords)

  for scanner.Scan() {
  fmt.Println(scanner.Text())
  }

  }

Writer
和Reader类似,Writer也对应的提供了多组方法。基础方法包括如下几个:

  func (b *Writer) Write(p []byte) (nn int, err error) // 写入n byte数据

  func (b *Writer) Reset(w io.Writer) // 重置当前缓冲区

  func (b *Writer) Flush() error // 清空当前缓冲区,将数据写入输出

此外,Writer也提供了多个方法方便我们进行数据写入操作:

  func (b *Writer) WriteByte(c byte) error // 写入一个字节

  func (b *Writer) WriteRune(r rune) (size int, err error) // 写入一个字符

  func (b *Writer) WriteString(s string) (int, error) // 写入一个字符串

更多GO标准库内容见 go-doc-zh

原文链接:https://blog.csdn.net/preyta/article/details/80655736

原文地址:https://www.cnblogs.com/show58/p/12394810.html

时间: 2024-10-09 14:07:20

Go标准库-带缓冲的IO(bufio)的相关文章

不带缓冲的IO的标准输入到标准输出

在POSIX标准中提供了函数open, read, write, lseek以及close提供不带缓冲的IO,这些函数都是使用文件描述符: 在Linux/Unix系统中将标准输入复制到标准输出简单实现如下: #include <unistd.h> #define BUFFSIZE 4096 int main(int argc, char **argv) { int n; char buf[BUFFSIZE]; while((n = read(STDIN_FILENO, buf, BUFFSIZ

带缓冲的IO和不带缓冲的IO

文件描述符: 文件描述符是一个小的非负整数,是内核用来标识特定进程正在访问的文件 标准输入/输出/出错: shell为每个程序打开了三个文件描述符,STDIN_FILEON,STDOUT_FILEON,STDERR_FILEON,默认这三个文件描述符都链向终端 不带缓冲的IO: 函数open read write lseek close提供了不用缓冲的IO.这些函数都使用文件描述符 size_t read(int fd,void *buf,size_t count) 从fd标识的文件中一次读取c

Go中常用包笔记 bufio:带缓冲的IO操作/SCANNER(二)

Package bufio 提供可缓存的IO访问   Scanner:    func NewScanner(r io.Reader) *Scanner //构造函数    func (s *Scanner) Buffer(buf []byte, max int) //指定使用的缓冲区    func (s *Scanner) Split(split SplitFunc) //设定切割函数 使用四个切割器    func (s *Scanner) Scan() bool  //扫描    fun

带缓冲IO和不带缓冲IO

不带缓冲IO是指read(),write()等函数 标准(带缓冲)IO是指fread(),fwrite()等函数 实际上缓冲有两种,是用户空间上的缓冲(流缓冲区)和内核缓冲区.无论是不带缓冲IO还是标准IO都要通过系统调用将数据输入到内核缓冲区. 所谓的带缓冲是指带流缓冲区. 可以参考文章http://blog.sina.cn/dpool/blog/s/blog_6592a07a0101gar7.html

带缓冲I/O 和不带缓冲I/O的区别与联系

首先要明白不带缓冲的概念:所谓不带缓冲,并不是指内核不提供缓冲,而是只单纯的系统调用,不是函数库的调用.系统内核对磁盘的读写都会提供一个块缓冲(在有些地方也被称为内核高速缓存),当用write函数对其写数据时,直接调用系统调用,将数据写入到块缓冲进行排队,当块缓冲达到一定的量时,才会把数据写入磁盘.因此所谓的不带缓冲的I/O是指进程不提供缓冲功能(但内核还是提供缓冲的).每调用一次write或read函数,直接系统调用. 而带缓冲的I/O是指进程对输入输出流进行了改进,提供了一个流缓冲,当用fw

走进C++程序世界------IO标准库介绍

流概述 流是C++标准的组成部分,流的主要目标是,将从磁盘读取文件或将输入写入控制台屏幕的问题封装起来,创建流后程序员就可以使用它,流将负责处理所有的细节. IO类库 在C++输入?输出操作是通过C++系统提供的完成I/O操作的一组类实现的.主要包括: 标准流类:处理与标准输入设备(键盘)和输出设备(显示器)关联的数据流 文件流类:处理与磁盘文件关联的数据流 字符串流类:利用内存中的字符数组处理数据的输入输出 异常类等:处理异常错误. 标准IO对象: 包含iostream类的C++程序启动时,将

C 标准库IO缓冲区和内核缓冲区的区别

1.C标准库的I/O缓冲区 UNIX的传统 是Everything is a file,键盘.显示器.串口.磁盘等设备在/dev 目录下都有一个特殊的设备文件与之对应,这些设备文件也可以像普通文件(保存在磁盘上的文件)一样打开.读.写和关闭,使用的函数接口是相同的.用户程序调用C标准I/O库函数读写普通文件或设备,而这些库函数要通过系统调用把读写请求传给内核 ,最终由内核驱动磁盘或设备完成I/O操作.C标准库为每个打开的文件分配一个I/O缓冲区以加速读写操作,通过文件的FILE 结构体可以找到这

C 标准库基础 IO 操作总结

其实输入与输出对于不管什么系统的设计都是异常重要的,比如设计 C 接口函数,首先要设计好输入参数.输出参数和返回值,接下来才能开始设计具体的实现过程.C 语言标准库提供的接口功能很有限,不像 Python 库.不过想把它用好也不容易,本文总结 C 标准库基础 IO 的常见操作和一些特别需要注意的问题,如果你觉着自己还不是大神,那么请相信我,读完全文后你肯定会有不少收获. 一.操作句柄 打开文件其实就是在操作系统中分配一些资源用于保存该文件的状态信息及文件的标识,以后用户程序可以用这个标识做各种读

浅谈C++ IO标准库(1)

IO流:一.C++中标准IO库:1).为面向对象的标准库.2).以继承的形式设计.     A)以iostream为基类,派生出了fstream,strigstream类.注意:fstream.stringstream没有继承关系,open.close为fstream类自有的函数操作,str为stringstream自有的函数操作,故其各函数操作不可混用,而iostream中的函数操作其两子类由于继承关系可以调用.     B) 其禁用了复制和赋值操作,故IO对象不可以复制或赋值.这将导致像ve