In programming, often you have multiple sollutions to do the same thing. I have identified 3 methods to list files in a given folder. Let's see some examples:
func ReadDir(dirname string) ([]os.FileInfo, error)
This example will list files and folders found in ./test. If the folder is not found you will get a fatal error using "log" package.
// list files
package main
import (
"fmt"
"io/ioutil"
"log"
)
func main() {
files, err := ioutil.ReadDir("./test")
if err != nil {
log.Fatal(err)
}
for _, file := range files {
fmt.Println(file.Name(), file.IsDir())
}
}
Try it: list-files
filepath.Walk can list files in a directory structure, it also allows us to recursively discover directories and files. Let's study this function:
func Walk(root string, walkFn WalkFunc) error
Walk walks the file tree rooted at root, calling walkFn for each file or directory in the tree, including root. All errors that arise visiting files and directories are filtered by walkFn. The files are walked in lexical order, which makes the output deterministic but means that for very large directories Walk can be inefficient. Walk does not follow symbolic links.
WalkFunc is a callback function signature you must create to call Walk() with it:
type WalkFunc func(path string, info os.FileInfo, err error) error
//walk function
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
err := filepath.Walk("./test",
func(path string, info os.FileInfo,
err error) error {
if err != nil {
fmt.Println(err)
return err
}
fmt.Printf("dir: %v: name: %s\n", info.IsDir(), path)
return nil
})
if err != nil {
fmt.Println(err)
}
}
>make run ./main dir: true: name: ./test dir: true: name: test/subfolder dir: false: name: test/subfolder/file21 dir: false: name: test/subfolder/file22 dir: false: name: test/test1 >
Try it: walk-function
os.File object, can be used on folders. With a File object can use Readdir() method. This will return a array slice with all the files in sthe directory associated with the respective file.
func (f *File) Readdir(n int) ([]FileInfo, error)
Readdir reads the contents of the directory associated with file and returns a slice of up to n FileInfo values, as would be returned by Lstat, in directory order. Subsequent calls on the same file will yield further FileInfos.
You can use parammeter n: If n > 0, Readdir returns at most n FileInfo structures. In this case, if Readdir returns an empty slice, it will return a non-nil error explaining why. At the end of a directory, the error is io.EOF. If n <= 0, Readdir returns all the FileInfo from the directory in a single slice.
//readir.go
package main
import (
"fmt"
"os"
)
// list files in a folder
func main() {
//open a folder
f, err := os.Open("./test")
if err != nil {
fmt.Println(err)
return
}
files, err := f.Readdir(0)
if err != nil {
fmt.Println(err)
return
}
for _, v := range files {
fmt.Println(v.Name(), v.IsDir())
}
}
Try it: file-readir
Reading and writing files are basic tasks needed for many Go programs. First we'll look at some examples of reading files.
//reading file
package main
import (
"bufio"
"fmt"
"io"
"os"
)
// This helper will streamline our error checks below.
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
f, err := os.Open("files/dat.txt")
check(err)
// Postpone closing
defer f.Close()
// Read some bytes
b1 := make([]byte, 12)
n1, err := f.Read(b1)
check(err)
fmt.Printf("%d bytes: %s\n", n1, string(b1[:n1]))
// You can jump using "Seek"
o2, err := f.Seek(6, 0)
check(err)
b2 := make([]byte, 2)
n2, err := f.Read(b2)
check(err)
fmt.Printf("%d bytes @ %d: ", n2, o2)
fmt.Printf("%v\n", string(b2[:n2]))
// Read at least
o3, err := f.Seek(3, 0)
check(err)
b3 := make([]byte, 10)
n3, err := io.ReadAtLeast(f, b3, 10)
check(err)
fmt.Printf("%d bytes @ %d: %s\n", n3, o3, string(b3))
// Seek(0, 0) accomplishes rewind
_, err = f.Seek(0, 0)
check(err)
// buffered reader
r4 := bufio.NewReader(f)
b4, err := r4.Peek(12)
check(err)
fmt.Printf("12 bytes: %s\n", string(b4))
}
Try it: read_file
Writing files in Go follows similar patterns.
package main
import (
"bufio"
"fmt"
"os"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
// To start, here's how to dump a string (or just bytes) into a file.
d1 := []byte("hello\ngo\n")
err := os.WriteFile("tmp/dat1", d1, 0644)
check(err)
// For more granular writes, open a file for writing.
f, err := os.Create("tmp/dat2")
check(err)
// It's idiomatic to defer a Close immediately
// after opening a file.
defer f.Close()
// You can Write byte slices as you'd expect.
d2 := []byte{115, 111, 109, 101, 10}
n2, err := f.Write(d2)
check(err)
fmt.Printf("wrote %d bytes\n", n2)
// A WriteString is also available.
n3, err := f.WriteString("writes\n")
check(err)
fmt.Printf("wrote %d bytes\n", n3)
// Issue a Sync to flush writes to stable storage.
f.Sync()
// bufio provides buffered writers in addition
// to the buffered readers we saw earlier.
w := bufio.NewWriter(f)
n4, err := w.WriteString("buffered\n")
check(err)
fmt.Printf("wrote %d bytes\n", n4)
// Use Flush to ensure all buffered operations have
// been applied to the underlying writer.
w.Flush()
}
Try it: file-writer
You can use temporary files for intermediate data processing jobs. You can use folder /temp or /tmp but you never know if this folder exist. Sometimes system temporary folder is redirected. Therefore is better to use Go API special design for this purpose.
// temp_files.go
package main
import (
"fmt"
"os"
"path/filepath"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
f, err := os.CreateTemp("", "sample")
check(err)
fmt.Println("Temp file name:", f.Name())
defer os.Remove(f.Name())
// We can write some data to the file.
_, err = f.Write([]byte{1, 2, 3, 4})
check(err)
// prefer to create a temporary *directory*.
dname, err := os.MkdirTemp("", "sampledir")
check(err)
fmt.Println("Temp dir name:", dname)
defer os.RemoveAll(dname)
// Now we can synthesize temporary file names by
// prefixing them with our temporary directory.
fname := filepath.Join(dname, "file1")
err = os.WriteFile(fname, []byte{1, 2}, 0666)
check(err)
}
Try it: file-writer
For advanced programming, you need these references. Learn all the fundtions. If you know a function exists you can check it's signature and examples.
Read next: Concurrency