golang bufio包中的Write方法分析

bufio包实现了带缓冲的I/O,它封装了io.Reader和io.Writer对象,然后创建了另外一种对象(Reader或Writer)实现了相同的接口,但是增加了缓冲功能。
首先来看没有缓冲功能的Write(os包中)方法,它会将数据直接写到文件中。

package main

import (
    "os"
    "fmt"
)

func main() {
    file, err := os.OpenFile("a.txt", os.O_CREATE|os.O_RDWR, 0666)
    if err != nil {
        fmt.Println(err)
    }
    defer file.Close()

    content := []byte("hello world!")
    if _, err = file.Write(content); err != nil {
        fmt.Println(err)
    }
    fmt.Println("write file successful")
}

接着看一个错误的使用带缓冲的Write方法例子,当下面的程序执行后是看不到写入的数据的。

package main

import (
    "os"
    "fmt"
    "bufio"
)

func main() {
    file, err := os.OpenFile("a.txt", os.O_CREATE|os.O_RDWR, 0666)
    if err != nil {
        fmt.Println(err)
    }
    defer file.Close()

    content := []byte("hello world!")
    newWriter := bufio.NewWriter(file)
    if _, err = newWriter.Write(content); err != nil {
        fmt.Println(err)
    }
    fmt.Println("write file successful")
}

为什么会在文件中看不到写入的数据呢,我们来看看bufio中的Write方法。

func (b *Writer) Write(p []byte) (nn int, err error){
    for len(p) > b.Available() && b.err == nil {
        var n int
        if b.Buffered() == 0{
            n,b.err =b.wr.Write(p)
        }else {
            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
}

Write方法首先会判断写入的数据长度是否大于设置的缓冲长度,如果小于,则会将数据copy到缓冲中;当数据长度大于缓冲长度时,如果数据特别大,则会跳过copy环节,直接写入文件。其他情况依然先会将数据拷贝到缓冲队列中,然后再将缓冲中的数据写入到文件中。
所以上面的错误示例,只要给其添加Flush()方法,将缓存的数据写入到文件中。

package main

import (
    "os"
    "fmt"
    "bufio"
)

func main() {
    file, err := os.OpenFile("./a.txt", os.O_CREATE|os.O_RDWR, 0666)
    if err != nil {
        fmt.Println(err)
    }
    defer file.Close()

    content := []byte("hello world!")
    newWriter := bufio.NewWriterSize(file, 1024)
    if _, err = newWriter.Write(content); err != nil {
        fmt.Println(err)
    }
    if err = newWriter.Flush(); err != nil {
        fmt.Println(err)
    }
    fmt.Println("write file successful")
}

你可能感兴趣的:(GO学习总结)