Home

Awesome

spf13/afero translate-svg

<!--[![explain]][source]-->

「 Go 的文件系统抽象系统 」

中文 | english


校对 ✅

<!-- doc-templite START generated --> <!-- repo = 'spf13/afero' --> <!-- commit = 'd40851caa0d747393da1ffb28f7f9d8b4eeffebd' --> <!-- time = '2018-09-07' -->
翻译的原文与日期最新更新更多
commit⏰ 2018-09-07last中文翻译
<!-- doc-templite END generated -->

贡献

欢迎 👏 勘误/校对/更新贡献 😊 具体贡献请看

生活

If help, buy me coffee —— 营养跟不上了,给我来瓶营养快线吧! 💰


afero logo-sm

Go 的文件系统抽象系统

Build Status Build status GoDoc Join the chat at https://gitter.im/spf13/afero

目录

<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> <!-- END doctoc generated TOC please keep comment here to allow auto update -->

概观

Afero 是一个文件系统框架,提供与任何文件系统的简单,统一和通用的交互 API。作为提供接口,类型和方法的抽象层,Afero 具有非常干净的接口和简单的设计,没有不必要的构造函数或初始化方法。

Afero 也是一个库,提供一组可互操作的后端文件系统,轻松地使用。同时保留 os 和 ioutil 包的所有功能和优点.

Afero 比单独使用 os 包提供了显着的改进,最显着的是能够在不依赖磁盘的情况下,创建模拟和测试文件系统.

它考虑到了,您想使用 OS 包的任何情况,因为它提供了额外的抽象,使得在测试期间可以轻松使用内存支持的文件系统。它还增加了对 http 文件系统的支持,以实现完全的互操作性.

Afero 特性

使用 Afero

Afero 易于使用,且简单明了.

您可以使用 Afero 的几种不同方式:

第 1 步:安装 Afero

首先使用 go get 安装最新版本的库.

$ go get github.com/spf13/afero

接下来在您的应用程序中,包含 Afero.

import "github.com/spf13/afero"

第 2 步:声明后端

首先定义一个包级变量,并将其设置为指向文件系统的指针.

var AppFs = afero.NewMemMapFs()

or

var AppFs = afero.NewOsFs()

重要的是要注意,如果重复调用,您将使用一个全新的隔离文件系统。在 OsFs 的情况下,它仍将使用相同的底层文件系统,但会降低根据需要放入其他文件系统的能力.

第 3 步:像操作系统包一样使用它

在整个应用程序中,使用您通常会使用的任何功能和方法.

所以,如果我以前的应用有:

os.Open('/tmp/foo')

我们将其替换为:

AppFs.Open('/tmp/foo')

AppFs是我们上面定义的变量.

所有可用功能的列表

文件系统方法可用:

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

文件接口和方法可用:

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

在某些应用程序中,定义一个只导出文件系统变量的新包,就可以从任何地方轻松访问。

使用 Afero 的实用功能

Afero 提供了一组函数,使其更易于使用底层文件系统。这些函数主要来自 io&ioutil,其中一些是为 Hugo 开发的.

afero 实用程序,支持所有 afero 兼容的后端.

实用程序列表包括:

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)

有关完整列表,请参阅Afero 的 GoDoc

这里是有两种不同的使用方法。

直接调用实用程序

fs := new(afero.MemMapFs)
f, err := afero.TempFile(fs,"", "ioutil-test")

通过 Afero 调用

fs := afero.NewMemMapFs()
afs := &afero.Afero{Fs: fs}
f, err := afs.TempFile("", "ioutil-test")

使用 Afero 进行测试

使用模拟文件系统进行测试有很大好处。每次初始化时,它都处于完全空白状态,无论操作系统如何,都可以轻松重现。您可以创建重要内容文件,文件访问速度快,同时还可以避免,删除临时文件,Windows 文件锁定等所有烦人的问题。MemMapFs 后端非常适合测试.

实现此目的的一种方法是定义如上所述的变量。在您的应用程序测试期间,这将被设置为afero.NewOsFs(),当然您也可以设为 afero.NewMemMapFs().

每个测试都初始化一个空白的平板内存后端并不少见。要做到这一点, 在我应用程序代码中适当的地方,定义appFS = afero.NewOsFs()。此方法可确保测试与顺序无关,并且没有依赖于早期测试留下的状态.

然后在我的测试中,我会为每个测试初始化一个新的 MemMapF:

func TestExist(t *testing.T) {
	appFS := afero.NewMemMapFs()
	// 创建 test 文件 和 目录
	appFS.MkdirAll("src/a", 0755)
	afero.WriteFile(appFS, "src/a/b", []byte("file b"), 0644)
	afero.WriteFile(appFS, "src/c", []byte("file c"), 0644)
	name := "src/c"
	_, err := appFS.Stat(name)
	if os.IsNotExist(err) {
		t.Errorf("file \"%s\" does not exist.\n", name)
	}
}

可用的后端

原生操作系统

OsFs

第一个是围绕原生 OS 调用的包装器。将它变得非常容易使用,因为所有调用都与现有的 OS 调用相同。它还使您的代码在操作系统,与根据需要使用模拟文件系统时,变得轻松,甚至无聊^_^

appfs := afero.NewOsFs()
appfs.MkdirAll("src/a", 0755))

内存支持存储

MemMapFs

Afero 还提供完全原子内存支持的文件系统,非常适合用于模拟,并在不需要保持时,加速不必要的磁盘。它是完全并发的,可以安全地在 go 协程中使用.

mm := afero.NewMemMapFs()
mm.MkdirAll("src/a", 0755))

InMemoryFile

作为 MemMapFs 的一部分,Afero 还提供原子的,完全并发的内存支持文件实现.这可以轻松地在其他内存支持的文件系统中使用.计划是使用 InMemoryFile 添加基数树内存存储文件系统.

网络接口

SftpFs

Afero 对安全文件传输协议(sftp)有实验性的支持。可用于加密通道上执行文件操作.

过滤后端

BasePathFs

BasePathF 将所有操作限制在 Fs 内的给定路径。在调用这个源 Fs 之前, Fs 操作的给定文件名,会以基本路径为前缀.

bp := afero.NewBasePathFs(afero.NewOsFs(), "/base/path")

ReadOnlyFs

源 Fs 周围的薄包装器,提供只读的.

fs := afero.NewReadOnlyFs(afero.NewOsFs())
_, err := fs.Create("/file.txt")
// err = syscall.EPERM

RegexpFs

对文件名进行过滤后的,任何与传递的正则表达式不匹配的文件,都将被视为不存在。将不会创建与提供的正则表达式不匹配的文件。目录不过滤.

fs := afero.NewRegexpFs(afero.NewMemMapFs(), regexp.MustCompile(`\.txt$`))
_, err := fs.Create("/file.html")
// err = syscall.ENOENT

HttpFs

Afero 提供了一个 http 兼容的后端,可以包装任何现有的后端.

Http 包需要稍微特定的 Open 版本,它返回一个 http.File 类型.

Afero 提供满足此要求的 httpFs 文件系统。任何 Afero FileSystem 都可以用作 httpFs。

httpFs := afero.NewHttpFs(<ExistingFS>)
fileserver := http.FileServer(httpFs.Dir(<PATH>)))
http.Handle("/", fileserver)

复合后端

Afero 提供合成两个文件系统(或更多),作为单个文件系统的能力.

CacheOnReadFs

CacheOnReadFs 将懒洋洋地将任何访问过的文件,从基础层-base复制到覆盖层-overlay中。后续读取将直接从覆盖层中提取,允许缓存持续时间内,请求在覆盖层中创建的缓存。

如果基本文件系统是可写的,则对文件的任何更改,将首先对基础层进行,然后对覆盖层进行。而打开文件的 Write 调用控制,如Write()Truncate()则先到覆盖层.

要仅将文件写入覆盖层,可以直接使用覆盖层 Fs(而不是通过联合 Fs).

在给定time.Duration缓存持续时间内,对该层中的文件进行缓存,缓存持续时间为 0 ,意味着"永远",意味着文件将不会从基础层重新请求.

只读的基础层会让覆盖层也是只读的,但是当文件在缓存层中不存在(或过时)时,仍然将文件从基础层复制到覆盖层.

base := afero.NewOsFs()
layer := afero.NewMemMapFs()
ufs := afero.NewCacheOnReadFs(base, layer, 100 * time.Second)

CopyOnWriteFs()

CopyOnWriteFs 是一个只读的基本文件系统,顶部有一个可写的层.

Read 操作首先查看覆盖层,如果没有找到,将从基础层提供文件服务.

只能在覆盖层中对文件系统进行更改.

任何仅在基础中找到的文件的修改,都会在修改(包括打开可写的文件)之前,将文件复制到覆盖层.

目前不允许删除和重命名,仅存在于基础层中的文件。如果文件在基础层和覆盖层中存在,则仅能删除/重命名覆盖层.

	base := afero.NewOsFs()
	roBase := afero.NewReadOnlyFs(base)
	ufs := afero.NewCopyOnWriteFs(roBase, afero.NewMemMapFs())

	fh, _ = ufs.Create("/home/test/file2.txt")
	fh.WriteString("This is a test")
	fh.Close()

在此示例中,所有写入操作仅发生在内存(MemMapFs)中, 基本文件系统(OsFs)保持不变.

期望/可能的后端

以下是我们希望有人可能实现的后端,简短列表:

关于该项目

这个名字是什么

Afero 来自拉丁美洲的 Ad-Facere.

**"Ad"**是一个前缀,意思是"to".

**"Facere"**是"make 或 do "的根单词"faciō"的一种形式.

afero 的字面含义是"to make"或"to do",这对于允许制作文件和目录,并使用它们进行操作的库来说非常合适.

与 Afero 具有相同根源的英语单词是"affair"。Affair 拥有相同的概念,但作为名词,它意味着"制造或完成的东西"或"特定类型的物体".

与我的其他一些库(hugo,cobra,viper)不同,谷歌一下也不错.

发行说明

贡献

  1. 叉-Fork 吧
  2. 创建您的功能分支(git checkout -b my-new-feature)
  3. 提交你的更改(git commit -am 'Add some feature')
  4. 推到分支(git push origin my-new-feature)
  5. 创建新的 Pull 请求

贡献者

名字没有特别的顺序:

执照

Afero 是在 Apache 2.0 许可下发布的。看到LICENSE.txt