go

How to read a text file?


I'm trying to read "file.txt" and put the contents into a variable using Golang. Here is what I've tried...

package main

import (
    "fmt"
    "os"
    "log"
)

func main() {
    file, err := os.Open("file.txt")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Print(file)
}

The file gets read successfully and the return from os.Open returns a type of *os.File


Solution

  • It depends on what you are trying to do.

    file, err := os.Open("file.txt")
    fmt.Print(file)
    

    The reason it outputs &{0xc082016240}, is because you are printing the pointer value of a file-descriptor (*os.File), not file-content. To obtain file-content, you may READ from a file-descriptor.


    To read all file content(in bytes) to memory, ioutil.ReadAll

    package main
    
    import (
        "fmt"
        "io/ioutil"
        "os"
        "log"
    )
    
    func main() {
        file, err := os.Open("file.txt")
        if err != nil {
            log.Fatal(err)
        }
        defer func() {
            if err = file.Close(); err != nil {
                log.Fatal(err)
            }
        }()
    
    
      b, err := io.ReadAll(file)
      fmt.Print(b)
    }
    

    But sometimes, if the file size is big, it might be more memory-efficient to just read in chunks: buffer-size, hence you could use the implementation of io.Reader.Read from *os.File

    func main() {
        file, err := os.Open("file.txt")
        if err != nil {
            log.Fatal(err)
        }
        defer func() {
            if err = file.Close(); err != nil {
                log.Fatal(err)
            }
        }()
    
    
        buf := make([]byte, 32*1024) // define your buffer size here.
    
        for {
            n, err := file.Read(buf)
    
            if n > 0 {
                fmt.Print(buf[:n]) // your read buffer.
            }
    
            if err == io.EOF {
                break
            }
            if err != nil {
                log.Printf("read %d bytes: %v", n, err)
                break
            }
        }
    
    }
    

    Otherwise, you could also use the standard util package: bufio, try Scanner. A Scanner reads your file in tokens: separator.

    By default, scanner advances the token by newline (of course you can customise how scanner should tokenise your file, learn from here the bufio test).

    package main
    
    import (
        "fmt"
        "os"
        "log"
        "bufio"
    )
    
    func main() {
        file, err := os.Open("file.txt")
        if err != nil {
            log.Fatal(err)
        }
        defer func() {
            if err = file.Close(); err != nil {
                log.Fatal(err)
            }
        }()
    
        scanner := bufio.NewScanner(file)
    
        for scanner.Scan() {             // internally, it advances token based on sperator
            fmt.Println(scanner.Text())  // token in unicode-char
            fmt.Println(scanner.Bytes()) // token in bytes
    
        }
    }
    

    Lastly, I would also like to reference you to this awesome site: go-lang file cheatsheet. It encompassed pretty much everything related to working with files in go-lang, hope you'll find it useful.