Path manipulation

The filepath package contains less than 20 functions, which is a small number compared to the packages of the standard library, and it's used to manipulate paths. Let's take a quick look at these functions:

  • func Abs(path string) (string, error)Returns the absolute version of the path that's passed by joining it to the current working directory (if it's not already absolute), and then cleans it.
  • func Base(path string) string: Gives the last element of the path (base). For instance, path/to/some/file returns the file. Note that if the path is empty, this function returns a . (dot) path.
  • func Clean(path string) string: Returns the shortest version of the path by applying a series of defined rules. It does operations like replacing . and .., or removing trailing separators.
  • func Dir(path string) string: Gets the path without its last element. This usually returns the parent directory of the element.
  • func EvalSymlinks(path string) (string, error): Returns the path after evaluating symbolic links. The path is relative if the provided path is also relative and doesn't contain symbolic links with absolute paths.
  • func Ext(path string) string: Gets the file extension of the path, the suffix that starts with the final dot of the last element of the path, and it's an empty string if there's no dot (for example, docs/file.txt returns .txt).
  • func FromSlash(path string) string: Replaces all / (slashes) found in the path with the operative system path separator. This function does nothing if the OS is Windows, and it executes a replacement under Unix or macOS .
  • func Glob(pattern string) (matches []string, err error): Finds all files matching the specified pattern. If there are no matching files, the result is nil. It doesn't report eventual errors that occur during path exploration. It shares syntax with Match.
  • func HasPrefix(p, prefix string) bool: This function is deprecated.
  • func IsAbs(path string) bool: Shows if the path is absolute or not.
  • func Join(elem ...string) string: Concatenates multiple path elements by joining them with the filepath separator. Note that this also calls Clean on the result.
  • func Match(pattern, name string) (matched bool, err error): Verifies that the given name matches the pattern, allowing the use of the wild char characters * and ?, and groups or sequences of characters using square brackets.
  • func Rel(basepath, targpath string) (string, error): Returns the relative path from the base to the target path, or an error if this is not possible. This function calls Clean on the result.
  • func Split(path string) (dir, file string): Divides the path into two parts using the final trailing slash. The result is usually the parent path and the file name of the input path. If there is no separator, dir will be empty and the file will be the path itself.
  • func SplitList(path string) []string: Returns a list of paths, separating them with the list separator character, which is : in Unix and macOS and ; in Windows.
  • func ToSlash(path string) string: Operates the opposite substitution that the FromSlash function executes, changing each path separator to a /, doing nothing on Unix and macOS, and executing the replacement in Windows.
  • func VolumeName(path string) string: This does nothing in platforms that aren't Windows. It returns the path component which refers to the volume. This is done for both local paths and network resources. 
  • func Walk(root string, walkFn WalkFunc) error: Starting from the root directory, this function travels recursively through the file tree, executing the walk function for each entry of the tree. If the walk function returns an error, the walk stops and that error is returned. The function is defined as follows:
type WalkFunc func(path string, info os.FileInfo, err error) error
Before moving on to the next example, let's introduce an important variable: os.Args. This variable contains at least one value, which is the path that invoked the current process. This can be followed by eventual arguments that are specified in the same call.

We want to realize a small application that lists and counts the number of files in a directory. We can use some of the tools we just saw to achieve this. 

An example of the list and count files is shown in the following code:

package main

import (
"fmt"
"os"
"path/filepath"
)

func main() {
if len(os.Args) != 2 { // ensure path is specified
fmt.Println("Please specify a path.")
return
}
root, err := filepath.Abs(os.Args[1]) // get absolute path
if err != nil {
fmt.Println("Cannot get absolute path:", err)
return
}
fmt.Println("Listing files in", root)
var c struct {
files int
dirs int
}
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
// walk the tree to count files and folders
if info.IsDir() {
c.dirs++
} else {
c.files++
}
fmt.Println("-", path)
return nil
})
fmt.Printf("Total: %d files in %d directories", c.files, c.dirs)
}