|  | 
 |  | 
 | A FileSystem Abstraction System for Go | 
 |  | 
 | [](https://travis-ci.org/spf13/afero) [](https://ci.appveyor.com/project/spf13/afero) [](https://godoc.org/github.com/spf13/afero) [](https://gitter.im/spf13/afero?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | 
 |  | 
 | # Overview | 
 |  | 
 | Afero is an filesystem framework providing a simple, uniform and universal API | 
 | interacting with any filesystem, as an abstraction layer providing interfaces, | 
 | types and methods. Afero has an exceptionally clean interface and simple design | 
 | without needless constructors or initialization methods. | 
 |  | 
 | Afero is also a library providing a base set of interoperable backend | 
 | filesystems that make it easy to work with afero while retaining all the power | 
 | and benefit of the os and ioutil packages. | 
 |  | 
 | Afero provides significant improvements over using the os package alone, most | 
 | notably the ability to create mock and testing filesystems without relying on the disk. | 
 |  | 
 | It is suitable for use in a any situation where you would consider using the OS | 
 | package as it provides an additional abstraction that makes it easy to use a | 
 | memory backed file system during testing. It also adds support for the http | 
 | filesystem for full interoperability. | 
 |  | 
 |  | 
 | ## Afero Features | 
 |  | 
 | * A single consistent API for accessing a variety of filesystems | 
 | * Interoperation between a variety of file system types | 
 | * A set of interfaces to encourage and enforce interoperability between backends | 
 | * An atomic cross platform memory backed file system | 
 | * Support for compositional file systems by joining various different file systems (see httpFs) | 
 | * Filtering of calls to intercept opening / modifying files, several filters | 
 | may be stacked. | 
 | * A set of utility functions ported from io, ioutil & hugo to be afero aware | 
 |  | 
 |  | 
 | # Using Afero | 
 |  | 
 | Afero is easy to use and easier to adopt. | 
 |  | 
 | A few different ways you could use Afero: | 
 |  | 
 | * Use the interfaces alone to define you own file system. | 
 | * Wrap for the OS packages. | 
 | * Define different filesystems for different parts of your application. | 
 | * Use Afero for mock filesystems while testing | 
 |  | 
 | ## Step 1: Install Afero | 
 |  | 
 | First use go get to install the latest version of the library. | 
 |  | 
 |     $ go get github.com/spf13/afero | 
 |  | 
 | Next include Afero in your application. | 
 | ```go | 
 | import "github.com/spf13/afero" | 
 | ``` | 
 |  | 
 | ## Step 2: Declare a backend | 
 |  | 
 | First define a package variable and set it to a pointer to a filesystem. | 
 | ```go | 
 | var AppFs afero.Fs = &afero.MemMapFs{} | 
 |  | 
 | or | 
 |  | 
 | var AppFs afero.Fs = &afero.OsFs{} | 
 | ``` | 
 | It is important to note that if you repeat the composite literal you | 
 | will be using a completely new and isolated filesystem. In the case of | 
 | OsFs it will still use the same underlying filesystem but will reduce | 
 | the ability to drop in other filesystems as desired. | 
 |  | 
 | ## Step 3: Use it like you would the OS package | 
 |  | 
 | Throughout your application use any function and method like you normally | 
 | would. | 
 |  | 
 | So if my application before had: | 
 | ```go | 
 | os.Open('/tmp/foo') | 
 | ``` | 
 | We would replace it with a call to `AppFs.Open('/tmp/foo')`. | 
 |  | 
 | `AppFs` being the variable we defined above. | 
 |  | 
 |  | 
 | ## List of all available functions | 
 |  | 
 | File System Methods Available: | 
 | ```go | 
 | Chmod(name string, mode os.FileMode) : error | 
 | Chtimes(name string, atime time.Time, mtime time.Time) : error | 
 | Create(name string) : File, error | 
 | Mkdir(name string, perm os.FileMode) : error | 
 | MkdirAll(path string, perm os.FileMode) : error | 
 | Name() : string | 
 | Open(name string) : File, error | 
 | OpenFile(name string, flag int, perm os.FileMode) : File, error | 
 | Remove(name string) : error | 
 | RemoveAll(path string) : error | 
 | Rename(oldname, newname string) : error | 
 | Stat(name string) : os.FileInfo, error | 
 | ``` | 
 | File Interfaces and Methods Available: | 
 | ```go | 
 | io.Closer | 
 | io.Reader | 
 | io.ReaderAt | 
 | io.Seeker | 
 | io.Writer | 
 | io.WriterAt | 
 |  | 
 | Name() : string | 
 | Readdir(count int) : []os.FileInfo, error | 
 | Readdirnames(n int) : []string, error | 
 | Stat() : os.FileInfo, error | 
 | Sync() : error | 
 | Truncate(size int64) : error | 
 | WriteString(s string) : ret int, err error | 
 | ``` | 
 | In some applications it may make sense to define a new package that | 
 | simply exports the file system variable for easy access from anywhere. | 
 |  | 
 | ## Using Afero's utility functions | 
 |  | 
 | Afero provides a set of functions to make it easier to use the underlying file systems. | 
 | These functions have been primarily ported from io & ioutil with some developed for Hugo. | 
 |  | 
 | The afero utilities support all afero compatible backends. | 
 |  | 
 | The list of utilities includes: | 
 |  | 
 | ```go | 
 | DirExists(path string) (bool, error) | 
 | Exists(path string) (bool, error) | 
 | FileContainsBytes(filename string, subslice []byte) (bool, error) | 
 | GetTempDir(subPath string) string | 
 | IsDir(path string) (bool, error) | 
 | IsEmpty(path string) (bool, error) | 
 | ReadDir(dirname string) ([]os.FileInfo, error) | 
 | ReadFile(filename string) ([]byte, error) | 
 | SafeWriteReader(path string, r io.Reader) (err error) | 
 | TempDir(dir, prefix string) (name string, err error) | 
 | TempFile(dir, prefix string) (f File, err error) | 
 | Walk(root string, walkFn filepath.WalkFunc) error | 
 | WriteFile(filename string, data []byte, perm os.FileMode) error | 
 | WriteReader(path string, r io.Reader) (err error) | 
 | ``` | 
 | For a complete list see [Afero's GoDoc](https://godoc.org/github.com/spf13/afero) | 
 |  | 
 | They are available under two different approaches to use. You can either call | 
 | them directly where the first parameter of each function will be the file | 
 | system, or you can declare a new `Afero`, a custom type used to bind these | 
 | functions as methods to a given filesystem. | 
 |  | 
 | ### Calling utilities directly | 
 |  | 
 | ```go | 
 | fs := new(afero.MemMapFs) | 
 | f, err := afero.TempFile(fs,"", "ioutil-test") | 
 |  | 
 | ``` | 
 |  | 
 | ### Calling via Afero | 
 |  | 
 | ```go | 
 | fs := new(afero.MemMapFs) | 
 | afs := &Afero{Fs: fs} | 
 | f, err := afs.TempFile("", "ioutil-test") | 
 | ``` | 
 |  | 
 | ## Using Afero for Testing | 
 |  | 
 | There is a large benefit to using a mock filesystem for testing. It has a | 
 | completely blank state every time it is initialized and can be easily | 
 | reproducible regardless of OS. You could create files to your heart’s content | 
 | and the file access would be fast while also saving you from all the annoying | 
 | issues with deleting temporary files, Windows file locking, etc. The MemMapFs | 
 | backend is perfect for testing. | 
 |  | 
 | * Much faster than performing I/O operations on disk | 
 | * Avoid security issues and permissions | 
 | * Far more control. 'rm -rf /' with confidence | 
 | * Test setup is far more easier to do | 
 | * No test cleanup needed | 
 |  | 
 | One way to accomplish this is to define a variable as mentioned above. | 
 | In your application this will be set to &afero.OsFs{} during testing you | 
 | can set it to &afero.MemMapFs{}. | 
 |  | 
 | It wouldn't be uncommon to have each test initialize a blank slate memory | 
 | backend. To do this I would define my `appFS = &afero.OsFs{}` somewhere | 
 | appropriate in my application code. This approach ensures that Tests are order | 
 | independent, with no test relying on the state left by an earlier test. | 
 |  | 
 | Then in my tests I would initialize a new MemMapFs for each test: | 
 | ```go | 
 | func TestExist(t *testing.T) { | 
 | 	appFS = &afero.MemMapFs{} | 
 | 	// create test files and directories | 
 | 	appFS.MkdirAll("src/a", 0755)) | 
 | 	appFS.WriteFile("src/a/b", []byte("file b"), 0644) | 
 | 	appFS.WriteFile("src/c", []byte("file c"), 0644) | 
 | 	testExistence("src/c", true, t) | 
 | } | 
 |  | 
 | func testExistence(name string, e bool, t *testing.T) { | 
 | 	_, err := appFS.Stat(name) | 
 | 	if os.IsNotExist(err) { | 
 | 	    if e { | 
 | 	        t.Errorf("file \"%s\" does not exist.\n", name) | 
 |     	} | 
 | 	} else if err != nil { | 
 |     	panic(err) | 
 | 	} else { | 
 |     	if !e { | 
 |     	    t.Errorf("file \"%s\" exists.\n", name) | 
 |     	} | 
 | 	} | 
 | } | 
 | ``` | 
 |  | 
 | ## Using Afero with Http | 
 |  | 
 | Afero provides an http compatible backend which can wrap any of the existing | 
 | backends. | 
 |  | 
 | The Http package requires a slightly specific version of Open which | 
 | returns an http.File type. | 
 |  | 
 | Afero provides an httpFs file system which satisfies this requirement. | 
 | Any Afero FileSystem can be used as an httpFs. | 
 |  | 
 | ```go | 
 | httpFs := &afero.HttpFs{SourceFs: <ExistingFS>} | 
 | fileserver := http.FileServer(httpFs.Dir(<PATH>))) | 
 | http.Handle("/", fileserver) | 
 | ``` | 
 |  | 
 | # Available Backends | 
 |  | 
 | ## OsFs | 
 |  | 
 | The first is simply a wrapper around the native OS calls. This makes it | 
 | very easy to use as all of the calls are the same as the existing OS | 
 | calls. It also makes it trivial to have your code use the OS during | 
 | operation and a mock filesystem during testing or as needed. | 
 |  | 
 | ## MemMapFs | 
 |  | 
 | Afero also provides a fully atomic memory backed filesystem perfect for use in | 
 | mocking and to speed up unnecessary disk io when persistence isn’t | 
 | necessary. It is fully concurrent and will work within go routines | 
 | safely. | 
 |  | 
 | ### InMemoryFile | 
 |  | 
 | As part of MemMapFs, Afero also provides an atomic, fully concurrent memory | 
 | backed file implementation. This can be used in other memory backed file | 
 | systems with ease. Plans are to add a radix tree memory stored file | 
 | system using InMemoryFile. | 
 |  | 
 | ## Desired/possible backends | 
 |  | 
 | The following is a short list of possible backends we hope someone will | 
 | implement: | 
 |  | 
 | * SSH/SCP | 
 | * ZIP | 
 | * TAR | 
 | * S3 | 
 | * Mem buffering to disk/network | 
 | * BasePath (where all paths are relative to a fixed basepath) | 
 |  | 
 | # Filters | 
 |  | 
 | You can add "filtering" to an Fs by adding a FilterFs to an existing Afero Fs | 
 | like | 
 | ```go | 
 |     ROFs := afero.NewFilter(AppFs) | 
 |     ROFs.AddFilter(afero.NewReadonlyFilter()) | 
 | ``` | 
 | The ROFs behaves like a normal afero.Fs now, with the only exception, that it | 
 | provides a readonly view of the underlying AppFs. | 
 |  | 
 | The FilterFs is run before the source Fs and may intercept the call to the | 
 | underlying source Fs and can modify the returned data. If it does not wish to | 
 | do so, it just returns the data from the source. | 
 |  | 
 | The `AddFilter` adds a new FilterFs before any existing filters. | 
 |  | 
 | ## Available filters | 
 |  | 
 | * NewReadonlyFilter() - provide a read only view of the source Fs | 
 | * NewRegexpFilter(*regexp.Regexp) - provide a filtered view on file names, any | 
 | file (not directory) NOT matching the passed regexp will be treated as | 
 | non-existing | 
 |  | 
 |  | 
 |  | 
 | # About the project | 
 |  | 
 | ## What's in the name | 
 |  | 
 | Afero comes from the latin roots Ad-Facere. | 
 |  | 
 | **"Ad"** is a prefix meaning "to". | 
 |  | 
 | **"Facere"** is a form of the root "faciō" making "make or do". | 
 |  | 
 | The literal meaning of afero is "to make" or "to do" which seems very fitting | 
 | for a library that allows one to make files and directories and do things with them. | 
 |  | 
 | The English word that shares the same roots as Afero is "affair". Affair shares | 
 | the same concept but as a noun it means "something that is made or done" or "an | 
 | object of a particular type". | 
 |  | 
 | It's also nice that unlike some of my other libraries (hugo, cobra, viper) it | 
 | Googles very well. | 
 |  | 
 | ## Release Notes | 
 |  | 
 | * **0.10.0** 2015.12.10 | 
 |   * Full compatibility with Windows | 
 |   * Introduction of afero utilities | 
 |   * Test suite rewritten to work cross platform | 
 |   * Normalize paths for MemMapFs | 
 |   * Adding Sync to the file interface | 
 |   * **Breaking Change** Walk and ReadDir have changed parameter order | 
 |   * Moving types used by MemMapFs to a subpackage | 
 |   * General bugfixes and improvements | 
 | * **0.9.0** 2015.11.05 | 
 |   * New Walk function similar to filepath.Walk | 
 |   * MemMapFs.OpenFile handles O_CREATE, O_APPEND, O_TRUNC | 
 |   * MemMapFs.Remove now really deletes the file | 
 |   * InMemoryFile.Readdir and Readdirnames work correctly | 
 |   * InMemoryFile functions lock it for concurrent access | 
 |   * Test suite improvements | 
 | * **0.8.0** 2014.10.28 | 
 |   * First public version | 
 |   * Interfaces feel ready for people to build using | 
 |   * Interfaces satisfy all known uses | 
 |   * MemMapFs passes the majority of the OS test suite | 
 |   * OsFs passes the majority of the OS test suite | 
 |  | 
 | ## Contributing | 
 |  | 
 | 1. Fork it | 
 | 2. Create your feature branch (`git checkout -b my-new-feature`) | 
 | 3. Commit your changes (`git commit -am 'Add some feature'`) | 
 | 4. Push to the branch (`git push origin my-new-feature`) | 
 | 5. Create new Pull Request | 
 |  | 
 | ## Contributors | 
 |  | 
 | Names in no particular order: | 
 |  | 
 | * [spf13](https://github.com/spf13) | 
 | * [jaqx0r](https://github.com/jaqx0r) | 
 | * [mbertschler](https://github.com/mbertschler) | 
 |  | 
 | ## License | 
 |  | 
 | Afero is released under the Apache 2.0 license. See | 
 | [LICENSE.txt](https://github.com/spf13/afero/blob/master/LICENSE.txt) |