Book Image

Go Programming Cookbook - Second Edition

By : Aaron Torres
Book Image

Go Programming Cookbook - Second Edition

By: Aaron Torres

Overview of this book

Go (or Golang) is a statically typed programming language developed at Google. Known for its vast standard library, it also provides features such as garbage collection, type safety, dynamic-typing capabilities, and additional built-in types. This book will serve as a reference while implementing Go features to build your own applications. This Go cookbook helps you put into practice the advanced concepts and libraries that Golang offers. The recipes in the book follow best practices such as documentation, testing, and vendoring with Go modules, as well as performing clean abstractions using interfaces. You'll learn how code works and the common pitfalls to watch out for. The book covers basic type and error handling, and then moves on to explore applications, such as websites, command-line tools, and filesystems, that interact with users. You'll even get to grips with parallelism, distributed systems, and performance tuning. By the end of the book, you'll be able to use open source code and concepts in Go programming to build enterprise-class applications without any hassle.
Table of Contents (16 chapters)

Working with directories and files

Working with directories and files can be difficult when you switch between platforms (Windows and Linux, for example). Go provides cross-platform support to work with files and directories in the os and ioutils packages. We've already seen examples of ioutils, but now we'll explore how to use them in another way!

How to do it...

The following steps cover how to write and run your application:

  1. From your Terminal or console application, create a new directory called ~/projects/go-programming-cookbook/chapter1/filedirs.
  2. Navigate to this directory.
  1. Run the following command:
          $ go mod init github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/filedirs

You should see a file called go.mod that contains the following contents:

module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/filedirs
  1. Copy tests from~/projects/go-programming-cookbook-original/chapter1/filedirs or use this as an exercise to write some of your own code!
  2. Create a file called dirs.go with the following contents:
        package filedirs

import (
"errors"
"io"
"os"
)

// Operate manipulates files and directories
func Operate() error {
// this 0755 is similar to what you'd see with Chown
// on a command line this will create a director
// /tmp/example, you may also use an absolute path
// instead of a relative one
if err := os.Mkdir("example_dir", os.FileMode(0755));
err != nil {
return err
}

// go to the /tmp directory
if err := os.Chdir("example_dir"); err != nil {
return err
}

// f is a generic file object
// it also implements multiple interfaces
// and can be used as a reader or writer
// if the correct bits are set when opening
f, err := os.Create("test.txt")
if err != nil {
return err
}

// we write a known-length value to the file and
// validate that it wrote correctly
value := []byte("hellon")
count, err := f.Write(value)
if err != nil {
return err
}
if count != len(value) {
return errors.New("incorrect length returned
from write")
}

if err := f.Close(); err != nil {
return err
}

// read the file
f, err = os.Open("test.txt")
if err != nil {
return err
}

io.Copy(os.Stdout, f)

if err := f.Close(); err != nil {
return err
}

// go to the /tmp directory
if err := os.Chdir(".."); err != nil {
return err
}

// cleanup, os.RemoveAll can be dangerous if you
// point at the wrong directory, use user input,
// and especially if you run as root
if err := os.RemoveAll("example_dir"); err != nil {
return err
}

return nil
}
  1. Create a file called files.gowith the following contents:
        package filedirs

import (
"bytes"
"io"
"os"
"strings"
)

// Capitalizer opens a file, reads the contents,
// then writes those contents to a second file
func Capitalizer(f1 *os.File, f2 *os.File) error {
if _, err := f1.Seek(0, io.SeekStart); err != nil {
return err
}

var tmp = new(bytes.Buffer)

if _, err := io.Copy(tmp, f1); err != nil {
return err
}

s := strings.ToUpper(tmp.String())

if _, err := io.Copy(f2, strings.NewReader(s)); err !=
nil {
return err
}
return nil
}

// CapitalizerExample creates two files, writes to one
//then calls Capitalizer() on both
func CapitalizerExample() error {
f1, err := os.Create("file1.txt")
if err != nil {
return err
}

if _, err := f1.Write([]byte(`this file contains a
number of words and new lines`)); err != nil {
return err
}

f2, err := os.Create("file2.txt")
if err != nil {
return err
}

if err := Capitalizer(f1, f2); err != nil {
return err
}

if err := os.Remove("file1.txt"); err != nil {
return err
}

if err := os.Remove("file2.txt"); err != nil {
return err
}

return nil
}
  1. Create a new directory named example and navigate to it.
  1. Create a main.go file with the following contents:
        package main

import "github.com/PacktPublishing/
Go-Programming-Cookbook-Second-Edition/
chapter1/filedirs"

func main() {
if err := filedirs.Operate(); err != nil {
panic(err)
}

if err := filedirs.CapitalizerExample(); err != nil {
panic(err)
}
}
  1. Run go run ..
  2. You may also run the following:
          $ go build
$ ./example

You should see the following output:

          $ go run . 
          
hello
  1. If you copied or wrote your own tests, go up one directory and run go test, and ensure that all tests pass.

How it works...

If you're familiar with files in Unix, the Go os library should feel very familiar. You can perform basically all common operations—Stat a file to collect attributes, collect a file with different permissions, and create and modify directories and files. In this recipe, we performed a number of manipulations to directories and files and then cleaned up after ourselves.

Working with file objects is very similar to working with in-memory streams. Files also provide a number of convenience functions directly, such as Chown, Stat, and Truncate. The easiest way to get comfortable with files is to make use of them. In all the previous recipes, we have to be careful to clean up after our programs.

Working with files is a very common operation when building backend applications. Files can be used for configuration, secret keys, as temporary storage, and more. Go wraps OS system calls using the os package and allows the same functions to operate regardless of whether you're using Windows or Unix.

Once your file is opened and stored in a File structure, it can easily be passed into a number of interfaces (we discussed these interfaces earlier). All the earlier examples can use os.File structures directly instead of buffers and in-memory data streams in order to operate on data stored on the disk . This may be useful for certain techniques, such as writing all logs to stderr and the file at the same time with a single write call.