Inspired by Python's pathlib, made better by Go.
pathlib
is an "object-oriented" package for manipulating filesystem path objects. It takes many cues from Python's pathlib, although it does not strictly adhere to its design philosophy. It provides a simple, intuitive, easy, and abstracted interface for dealing with many different types of filesystems.
pathlib
is currently in the beta stage of development. The API is not guaranteed to be solidified, however changes will be as minimal as possible.
Beacuse pathlib
treats afero
filesystems as first-class citizens, you can instantiate a Path
object with the filesystem of your choosing.
package main
import (
"fmt"
"os"
"github.com/chigopher/pathlib"
"github.com/spf13/afero"
)
func main() {
// Create a path on your regular OS filesystem
path := pathlib.NewPathAfero("/home/ltclipp", afero.NewOsFs())
subdirs, err := path.ReadDir()
if err != nil {
fmt.Printf("%v\n", err)
os.Exit(1)
}
for _, dir := range subdirs {
fmt.Println(dir.Name())
}
}
[ltclipp@landon-virtualbox examples]$ go build .
[ltclipp@landon-virtualbox examples]$ ./examples | tail
Music
Pictures
Public
Templates
Videos
git
go
mockery_test
snap
software
package main
import (
"fmt"
"os"
"github.com/chigopher/pathlib"
"github.com/spf13/afero"
)
func main() {
// Create a path using an in-memory filesystem
path := pathlib.NewPathAfero("/", afero.NewMemMapFs())
hello := path.Join("hello_world.txt")
hello.WriteFile([]byte("hello world!"), 0o644)
subpaths, err := path.ReadDir()
if err != nil {
fmt.Printf("%v\n", err)
os.Exit(1)
}
for _, subpath := range subpaths {
fmt.Printf("Name: %s Mode: %o Size: %d\n", subpath.Name(), subpath.Mode(), subpath.Size())
}
bytes, _ := hello.ReadFile()
fmt.Println(string(bytes))
}
[ltclipp@landon-virtualbox examples]$ go build
[ltclipp@landon-virtualbox examples]$ ./examples
Name: hello_world.txt Mode: 644 Size: 12
hello world!
The design philosophy of this package is to be as thin of a layer as possible to existing community-standard packages, like io
, afero
, and os
. Additional functionality is provided in consise and logical ways to extend the existing community APIs.
The API of filepath.Path
can be grouped into a few main categories:
github.com/spf13/afero.Fs
wrappers: these are methods that have nearly identical signatures toafero.Fs
, with the exception of the path string (which is stored in thepathlib.Path
object itself.afero.Fs
is an object that is meant to interact directly with the filesystem.github.com/spf13/afero.Afero
wrappers: these are methods that again have nearly identical signatures toafero.Afero
.afero.Afero
is a convenience object that provides higher-level behavior to the underlyingafero.Fs
object.- Filesystem-specific methods: these are methods that are implemented by some, but not all, of the afero filesystems. These methods may fail at runtime if the filesystem you provide does not implement the required interface.
- Python's Pathlib-inspired methods: these are methods that are not implemented in the previous two steps, and that provide the power behind the object-oriented design.
github.com/chigopher/pathlib
-specific methods: these are miscellaneous methods that are not covered by any of the previous categories. These methods are typically conveniences around methods in one of the previous categories.
filepath.File
is intended to be a thin wrapper around afero.File
. We avoid simply returning this interface on calls to Open()
and OpenFile()
(etc) because we want the ability to extend our API beyond what afero
provides. So, we create our own File
object which embeds afero.File
, but might possibly contain further functionality.
github.com/spf13/afero
is a package that provides an abstracted interface to the underlying filesystem API calls. pathlib
uses this package for operating on the abstracted filesystem. This is powerful because it allows you to to use essentially any kind of filesystem that you want. Additionally, afero is a first-class-citizen in pathlib
meaning that you can implement and explicitly provide your own afero object.
The basic diagram looks like this:
Why pathlib
and not filepath
?
filepath
is a package that is tightly coupled to the OS filesystem APIs and also is not written in an object-oriented way. pathlib
uses afero
under the hood for its abstracted filesystem interface, which allows you to represent a vast array of different filesystems (e.g. SFTP, HTTP, in-memory, and of course OS filesystems) using the same Path
object.
You certainly could, however afero
does not represent a filesystem object in an object-oriented way. It is only object-oriented with respect to the filesystem itself. pathlib
is simply a thin layer on top of afero
that provides the filesystem-object-orientation.
Most certainly! pathlib
allows you to create in-memory filesystems, which have the nice property of being automatically garbage collected by Golang's GC when they go out of scope. You don't have to worry about defering any Remove()
functions or setting up temporary dirs in /tmp
. Just instantiate a MemMapFs
and you're good to go!
Currently only POSIX-style paths are supported.