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 型写入函数。

  • 相关阅读:
    MongoDB 3.0安全权限访问控制(Windows版)
    MVC创建通用DropdownList
    当文字超出宽度,自动截取文字并加省略号
    JQuery Datatables(二)
    JQuery Datatables(一)
    PHP signal 信号
    phpunit 入门
    Wget 命令详解
    ubuntn下 apt的用法和yum的比较(转)
    navicat for mysql 安装
  • 原文地址:https://www.cnblogs.com/yelao/p/14511711.html
Copyright © 2011-2022 走看看