zoukankan      html  css  js  c++  java
  • GoLang 文件缓冲 bufio.Writer 源码解析

    最近接触到 go 语言相关的 fileserver 项目,夯实基础,以图后效

    bufio.Writer 类型定义

    // Writer implements buffering for an io.Writer object.
    // If an error occurs writing to a Writer, no more data will be
    // accepted and all subsequent writes, and Flush, will return the error.
    // After all data has been written, the client should call the
    // Flush method to guarantee all data has been forwarded to
    // the underlying io.Writer.
    type Writer struct {
    	err error
    	buf []byte
    	n   int
    	wr  io.Writer
    }

     bufio包中Writer类型对 io.Writer 进行了包装,各字段说明:

    • err: 用于记录异常
    • buf: 用于缓冲的Slice, 默认大小 defaultBufSize = 4096 
      • const (
        	defaultBufSize = 4096
        )
        
        // NewWriter returns a new Writer whose buffer has the default size.
        func NewWriter(w io.Writer) *Writer {
        	return NewWriterSize(w, defaultBufSize)
        }
    • n: buf 中已经缓存的字节数,并且提供了一个访问方法
      • // Buffered returns the number of bytes that have been written into the current buffer.
        func (b *Writer) Buffered() int { return b.n }

        // Available returns how many bytes are unused in the buffer.
        func (b *Writer) Available() int { return len(b.buf) - b.n }

    bufio.Writer 的写实现

    // Write writes the contents of p into the buffer.
    // It returns the number of bytes written.
    // If nn < len(p), it also returns an error explaining
    // why the write is short.
    func (b *Writer) Write(p []byte) (nn int, err error) {
         // 如果待写数据长度大于缓存可接收长度 for len(p) > b.Available() && b.err == nil { var n int
              // 如果当前 buffer 中没有缓存数据, 则不经过缓存,直接将数据写入文件 if b.Buffered() == 0 { // Large write, empty buffer. // Write directly from p to avoid copy. n, b.err = b.wr.Write(p) } else { // 如果当前 buffer 中 有数据,则将待写数据塞满 buffer 后flush到文件中,进入下一次判断 n = copy(b.buf[b.n:], p) b.n += n b.Flush() } nn += n p = p[n:] }
         // 如果待写数据长度 小于 缓存可接收长度, 则直接写入缓存 if b.err != nil { return nn, b.err } n := copy(b.buf[b.n:], p) b.n += n // 调整缓存字节数 nn += n // 本次写入字节数,用于返回 return nn, nil }

    写逻辑:

    if: 待写数据长度大于缓存可接收长度 {
    
      if: 当前 buffer 中没有缓存数据 {
    
        则不经过缓存,直接将数据写入文件
      } 
    
      else: 当前 buffer 中有数据 {
    
        则将待写数据塞满 buffer 后flush到文件中,进入下一次判断
    
      }
    
    }
    
    else: 待写数据长度 小于 缓存可接收长度 {
    
       则直接写入缓存
    
    }

    补充1: io.Writer 功能, io包中Writer方法功能(返回值n 为成功写入的数据,如果 n 小于 待写入数据长度则报error,注意即使报错也有n个字节数据被写入

    // Writer is the interface that wraps the basic Write method.
    //
    // Write writes len(p) bytes from p to the underlying data stream.
    // It returns the number of bytes written from p (0 <= n <= len(p))
    // and any error encountered that caused the write to stop early.
    // Write must return a non-nil error if it returns n < len(p).
    // Write must not modify the slice data, even temporarily.
    //
    // Implementations must not retain p.
    type Writer interface {
    	Write(p []byte) (n int, err error)
    }

    补充2: Flush 实现,主要三个功能(将缓存数据写入文件, 写入错误重置缓存, 写入成功缓存索引置零)

    // Flush writes any buffered data to the underlying io.Writer.
    func (b *Writer) Flush() error {
    	if b.err != nil {
    		return b.err
    	}
    	if b.n == 0 {
    		return nil
    	}
         // 将缓存数据写到文件 n, err := b.wr.Write(b.buf[0:b.n]) if n < b.n && err == nil { err = io.ErrShortWrite } if err != nil { if n > 0 && n < b.n { // 出现错误时,重置 buffer(删除buffer中错误前已经写入到文件的字节数) copy(b.buf[0:b.n-n], b.buf[n:b.n]) } b.n -= n b.err = err return err }
         // 缓存索引置零 b.n = 0 return nil }

    至此,bufio Writer 写入数据的实现逻辑分析完毕。

    一些思考:

    在go的文件 buffer 型写入实现方式中,使用定义slice 作为内存缓存的方式缓冲写入的数据,当待写入数据的长度大于当前 slice 剩余空间(buffer 的 可接收数据长度)或者调用flush 将slice数据写入文件。

    可以关注学习操作系统层级的文件缓存,是否有不使用go语言slice作为buf,而使用操作系统提供的 buffer 型写入函数。

  • 相关阅读:
    [saiku] 系统登录成功后查询Cubes
    216. Combination Sum III
    215. Kth Largest Element in an Array
    214. Shortest Palindrome
    213. House Robber II
    212. Word Search II
    211. Add and Search Word
    210. Course Schedule II
    分硬币问题
    开始学习Python
  • 原文地址:https://www.cnblogs.com/yelao/p/14511711.html
Copyright © 2011-2022 走看看