美文网首页
go 读取文件操作

go 读取文件操作

作者: wayyyy | 来源:发表于2022-08-06 21:35 被阅读0次

    原文:超全总结:Go 读文件的 10 种方法

    整个文件读入内存中

    使用 ioutil.ReadFile
    package main
    
    import (
        "io/ioutil"
        "fmt"
    )
    
    func main() {
        content, err := ioutil.ReadFile("a.txt")
        if err != nil {
            panic(err)
        }
        fmt.Println(string(content))
    }
    
    使用os.ReadFile
    package main
    
    import (
        "fmt"
        "os"
    )
    
    func main() {
        content, err := os.ReadFile("a.txt")
        if err != nil {
            panic(err)
        }
        fmt.Println(string(content))
    }
    
    使用 ioutil.ReadAll
    package main
    
    import (
        "os"
        "io/ioutil"
        "fmt"
    )
    
    func main() {
        file, err := os.Open("a.txt")
        if err != nil {
            panic(err)
        }
        defer file.Close()
    
        content, err := ioutil.ReadAll(file)
        fmt.Println(string(content))
    }
    

    对于大文件,整个文件一次读取,有内存溢出的问题,因此一般并不推荐一次将整个文件读入到内存中。


    每次只读取一行

    一次性读取所有的数据,太耗费内存,因此可以指定每次只读取一行数据,工作中我们也需要处理日志类数据。

    使用 bufio.ReadBytes
    package main
    
    import (
        "bufio"
        "fmt"
        "io"
        "os"
        "strings"
    )
    
    func main() {
        // 创建句柄
        fi, err := os.Open("christmas_apple.py")
        if err != nil {
            panic(err)
        }
        defer fi.Close()
    
        // 创建 Reader
        r := bufio.NewReader(fi)
        for {
            lineBytes, err := r.ReadBytes('\n')
            line := strings.TrimSpace(string(lineBytes))
            if err != nil && err != io.EOF {
                panic(err)
            }
            if err == io.EOF && line == "" {
                break
            }
            fmt.Println(line)
        }
    }
    
    使用 bufio.ReadString
    package main
    
    import (
        "bufio"
        "fmt"
        "io"
        "os"
        "strings"
    )
    
    func main() {
        // 创建句柄
        fi, err := os.Open("a.txt")
        if err != nil {
            panic(err)
        }
        defer fi.Close()
    
        // 创建 Reader
        r := bufio.NewReader(fi)
        for {
            line, err := r.ReadString('\n')
            line = strings.TrimSpace(line)
            if err != nil && err != io.EOF {
                panic(err)
            }
            if err == io.EOF && line == "" {
                break
            }
            fmt.Println(line)
        }
    }
    

    块读取

    通用的做法是:

    • 先创建一个文件句柄,可以使用 os.Open 或者 os.OpenFile
    • 然后 bufio.NewReader 创建一个 Reader
    • 然后在 for 循环里调用 Reader 的 Read 函数,每次仅读取固定字节数量的数据。
    package main
    
    import (
        "bufio"
        "fmt"
        "io"
        "os"
    )
    
    func main() {
        // 创建句柄
        fi, err := os.Open("a.txt")
        if err != nil {
            panic(err)
        }
        defer fi.Close()
    
        buf := make([]byte, 1024)   // 每次读取 1024 个字节
        r := bufio.NewReader(fi)
        for {
            n, err := r.Read(buf)
            if err != nil && err != io.EOF {
                panic(err)
            }
    
            if n == 0 {
                break
            }
    
            fmt.Println(string(buf[:n]))
        }
    }
    
    使用 syscall 库

    os 库本质上也是调用 syscall 库,这里直接使用对于read系统调用的封装。

    package main
    
    import (
        "fmt"
        "sync"
        "syscall"
    )
    
    func main() {
        fd, err := syscall.Open("christmas_apple.py", syscall.O_RDONLY, 0)
        if err != nil {
            fmt.Println("Failed on open: ", err)
        }
        defer syscall.Close(fd)
    
        var wg sync.WaitGroup
        wg.Add(2)
        dataChan := make(chan []byte)
        go func() {
            wg.Done()
            for {
                data := make([]byte, 100)
                n, _ := syscall.Read(fd, data)
                if n == 0 {
                    break
                }
                dataChan <- data
            }
            close(dataChan)
        }()
    
        go func() {
            defer wg.Done()
            for {
                select {
                case data, ok := <-dataChan:
                    if !ok {
                        return
                    }
    
                    fmt.Printf(string(data))
                default:
    
                }
            }
        }()
        wg.Wait()
    }
    

    相关文章

      网友评论

          本文标题:go 读取文件操作

          本文链接:https://www.haomeiwen.com/subject/ajsvwrtx.html