一次编写,随处存储Go的可扩展文件系统
照片由Caroline Selfors在Unsplash上拍摄
我正在为飞机旅行收拾行李箱,我刚刚意识到我没有足够的空间来放我所有的衣服。我的手提箱以前工作得很好——显然我的需求发生了变化。
我可以把所有东西都塞进去,然后用绳子把它系起来。或者我可以把多余的衣服塞进三个购物袋,然后把四个都带过机场?这看起来不太好。拼凑或彻底改变我存放衣服的方式是一种糟糕的旅行计划方式——我需要更好的东西。更简单的东西。当然,我真正需要的只是一个更大的手提箱。手提箱是可以互换的,只需将衣服从一个换到另一个。
我的困境现在有点愚蠢和明显,但事实证明可交换存储也非常适合软件存储。便携式软件的梦想是"一次编写,随处运行"。软件也应该有可移植性数据。无论您是将数据存储在 S3 存储桶、磁盘还是 Web 浏览器中,它们都应该可以轻松互换。
便携式软件的梦想是"一次编写,随处运行"。软件也应该有可移植的数据。
不幸的是,它通常不是那么简单:每个新的数据"手提箱"不能以相同的方式放置,使用非常规的包装,或者如果你看起来很有趣,它就会分崩离析。如果没有共同的标准或审查过程,就很难为您的程序确定一个存储系统。不需要更改您的程序以符合独特的存储系统,并且适应未来的变化应该不难。我们需要用于不同类型存储的通用接口和一个共享测试套件来审查它们。标准存储箱
通用存储标准可以帮助解决这些问题,但它们需要在社区中广泛采用才能发挥作用。采用标准的第一步是在熟悉的设计和熟悉的来源中引入它。例如, Go在标准库中引入了文件系统接口,为开发人员的构建奠定了基础。它使用不起眼的文件,一个熟悉的数据包,组织在文件夹中,形成一个文件系统。Go 的"分层"文件系统模式是一个不错的选择,因为它已经在其他领域广泛使用。从智能手机上的相册到网络浏览器中的书签,文件系统模式在当今软件中无处不在。文件系统似乎是通用存储接口的绝佳选择。
在Hackpad的开发过程中,我们的存储系统开始出现裂痕,但我们缺乏修复它的工具。我们的大多数组件都需要使用几种不同的存储系统来读取和写入数据。对于每个新的存储系统,我们每次都编写和重写适配器代码——它造成了大量的流失。它从一个简单的内存存储开始,然后发展为流式.tar.gz文件阅读器,然后是覆盖文件系统。当我们也需要添加基于浏览器的存储时,很明显:需要一个新的、灵活的抽象。
在本文中,我们将讨论 Go 程序的一种新的、可扩展的文件系统模式及其工作原理。Go 的文件系统接口io/fs.FS为新的可能性打开了大门。让我们用 HackpadFS 把这扇门打开。HackpadFS
我们开源了我们的库HackpadFS,以定义通用文件系统接口并共享严格的测试套件,使每个人都可以制作自定义和可移植的文件系统。它将 Go 的入门文件系统提升到了一个全新的水平:50 多个小型、可组合的文件和 FS 接口多层覆盖文件系统内置文件系统:本机、内存、Web 浏览器、流媒体等用于合规性和一致性的严格测试套件
接下来,让我们用 HackpadFS 的内置文件系统、通用接口和成熟的测试套件探索新的可能性。内置文件系统
文件系统或 FS 是由"路径"定位的文件的集合。如果您之前使用过 Goos包,那么您已经使用过 FS。但是,重要的是要注意os包的静态函数不能用作实现通用接口的对象。它不能与其他实现交换,并且您的数据仅在一种存储中。Go 的io/fs.FS界面让我们一瞥可交换文件系统的可能性。使用 HackpadFS,我们可以在不重写代码的情况下尝试各种新的存储系统。
将相同的数据放入新的存储中。照片由Aleksei Ieshkin在Unsplash上拍摄
HackpadFS 附带了几个强大的文件系统。其中每一个都符合 HackpadFS 的新接口和io/fs.FS强大的冲击力:os.FS– 熟悉的os包裹。使用新的接口设计实现标准库中所有熟悉的行为。mem.FS– 内存中的 FS。indexeddb.FS– 与 WebAssembly 兼容的 FS,在后台使用 Web 浏览器的IndexedDB API。tar.ReaderFS- 流式 tar 归档文件 FS,用于内存和时间受限的程序。mount.FS– "覆盖"FS。能够在彼此之上安装文件系统。keyvalue.FS– 一个通用的键值对 FS。非常适合快速编写自己的 FS。mem.FS并indexeddb.FS建立在它之上。cache.ReadOnlyFS– 一个只读缓存,包装另一个 FS。
将其中一些组合在一起可以创建真正创新的程序,而无需对单个存储系统进行硬编码。
作为一个真实的例子,Hackpad现在使用其中的大部分在浏览器中构建 Go IDE。查看GitHub 上的源代码。
寻找灵感来创建自己的 FS?这里有一些想法:从 S3 存储桶 FS 中的文件(例如s3.FS.通过 Dropbox、Google Drive 或 OneDrive FS 与其他设备共享。将文件更改提交到 Git,就像go-git/go-git.使用 SSH FS 编辑远程服务器上的文件。知名接口的威力
Go 1.16 首次推出了新io/fs包,展示了用于实现只读文件系统的标准接口。它还演示了通过 HTTP 从任何兼容的文件系统通过net/http.FS. HackpadFS 项目受到这种方法的启发,为所有 Go 程序创建通用接口。早期的灵感也来自spf13/aferoand go-git/go-billy,尽管 HackpadFS 采用了不同的方法,为自定义文件系统提供模块化接口,并捆绑了严格的测试套件以实现严格的一致性。
众所周知的界面可帮助开发人员制作创意组合,但他们所定义的只是不同系统的交互方式。HackpadFS 通过共享许多模仿 Go和包的小型且可组合的接口来授权开发人员。要实现自定义 FS,您只需要编写最少的代码。osio/fs
例如,要创建一个foo.FS只添加的 new Lstat(),我们可以编写一个只有 2 个方法的完整 FS 结构:包 foo导入"github.com/hack-pad/hackpadfs"输入 FS 结构 {}func NewFS() (*FS, error) { return &FS{}, nil }func (fs *FS) Open(name string) (hackpadfs.File, error) { // ... }func (fs *FS) Lstat(name string) (hackpadfs.FileInfo, error) { // ... }// 类型 *FS 实现标准库的 FS 和 hackpadfs.LstatFS: var _ interface { hackpadfs.FS hackpadfs.LstatFS } = &FS{}
处理接口类型可能很棘手,因此 HackpadFS 还包含帮助函数来简化代码。现在任何人都可以使用foo.FShelpershackpadfs.Lstat(fooFS, "bar")来避免对泛型进行类型检查hackpadfs.FS。如果事实证明 FS 不支持相应的接口或兼容的接口,则返回"未实现"错误。新标准接口
那么,HackpadFS 包含哪些 Go 不包含的内容?这是所有新旧接口的快速细分,以及我们如何扩展它们。
Go 的内置接口包括FS、File、FileInfo和DirEntry. 另一方面,HackpadFS 为兼容性定义了等效接口,然后再定义了27个:
所有这些接口都可以使用您需要的任何功能来组成您自己的 FS。
Go 还实现了几个帮助函数以使 FS 处理更简单。HackpadFS 实现了大多数相同的助手,然后还有23个:常见错误
对我们来说,一个常见的麻烦来源是处理错误。理想情况下,我们可以使用errors.Is()orerrors.As()来检测某些类型的错误,但我们需要检查的值高度不一致。有时我们可以检查标准库错误,例如fs.ErrExist.,但有时我们被迫拉入syscall包以正确检测诸如"不是目录"之类的错误。
HackpadFS 通过包含一组行为正确且一致的统一错误来解决此问题:共享测试套件
最后但并非最不重要的一点是:如果文件系统不发挥作用,那么它就是不好的。为了确保严格的一致性,HackpadFS 提供了一个共享的测试套件,fstest来检查每个文件系统是否与包的行为相同os。
它旨在易于针对自定义文件系统使用,并且只会对实现它们的文件系统运行特定接口的测试。例如,让我们测试一下foo.FS:包 foo进口( "测试" "github.com/hack-pad/hackpadfs/fstest" )func TestFS(t *testing.T) { t.Parallel() options := fstest.FSOptions{ Name: "foo", TestFS: func(tb testing.TB) fstest.SetupFS { fs, err := NewFS() if err != nil { tb.Fatal(err) } return fs }, } fstest.FS(t, options) fstest.File(t, options) }
两者fstest.FS()及fstest.File()以上都启动了大量的子测试。每个子测试调用TestFS()创建新foo.FS实例,然后并行运行它们。由于foo.FS仅实现FSand LstatFS,因此只有那些测试会运行——所有其他测试都将被跳过。文件也是如此:如果返回的文件Open()仅支持读取操作,则仅运行文件读取测试。
测试套件是严格的,以确保非常严格的合规性和与os包行为的一致性。没有什么比一个不像一个文件系统更糟糕的了。今天,在文件系统上fstest运行90次测试和在文件上运行50次测试,总共556个断言。它已集成到所有 6 个内置文件系统的 CI 测试中。试一试
我们认为共享通用接口和严格的测试套件将有助于为 Go 社区创建一个强大的文件系统生态系统。HackpadFS 界面的可组合性及其内置文件系统可以在编写下一个应用程序时为每个人提供动力。去获取 github.com/hack-pad/hackpadfs
我们希望您能尝试一下 HackpadFS!把它放在一起真的很有趣,我们很想知道你是否有反馈。
秦岭七十二峪哪个最美?秦岭北麓七十二峪,分布在蓝田长安扈邑周至四县,每条峪道特质不一。或文人墨客咏怀言志或帝王贵族避暑狩猎或终南隐士隐于田园,每条都有独特的风景,四时皆景。蓝田县清峪秦岭的香格里拉,葫芦
首批国家级旅游休闲街区名单公示央广网北京1月11日消息(记者孙晓晨)国家发展改革委1月10日公示首批国家级旅游休闲街区名单,北京市东城区前门大街北京市朝阳区三里屯太古里天津市西青区杨柳青古镇街区等55个街区入选
情系梆子戏心怀家国梦原标题情系梆子戏心怀家国梦(主题)记全国文化和旅游系统劳动模范王洪玲(副题)中国旅游报见习记者杨丽敏人如其名,她的嗓音洪亮,像银铃一样清脆,听她唱戏是一种享受。这是戏迷对中国戏剧梅
板栗坳中的脚印和声音史语所图书馆旧址外景史语所离开之前立的留别李庄栗峰碑铭今日李庄码头陆晓娅这几年,四川宜宾的李庄古镇日渐热闹起来,人们到那儿看抗战时期的同济大学旧址国立中央博物院旧址,看被特意标上梁
日本的佛教圣地之高野山今天受到日本南海电车公司的邀请,有幸去访问了日本著名的佛教圣地高野山。高野山位于日本关西地区的和歌山县,从大阪难波搭乘南海电车大概需要2个小时左右的车程。公元816年日本当时的嵯峨
BruderEX8露营拖车优秀的户外续航能力可谓探险好伙伴尽管标准的露营车屋十分便利,但本身就具备动力系统也让维护变得较为麻烦,从这个角度来切入的话就会让露营拖车和露营车壳变成比较优良的选择,而露营车壳在使用的时候必须先行安装上车,露营拖
紫藤花隧道中的网红小火车前段时间,和海田园的网红小火车和紫藤花隧道突然火了起来,不得不说,视频拍的真的很漂亮!于是,作为一个老四川人,我立即就出发去打卡了。和海田园的管理者真的很聪明了,区别于大众化的花海
土库曼斯坦地狱之门燃烧50年,总统下令专家找扑灭办法位于土库曼斯坦境内沙漠地带的巨大天然气坑洞已经燃烧了50年,有地狱之门之称,现在成为世界著名景点。然而,由于它所带来的负面影响,该国领导人命令专家们想尽办法扑灭。当地时间1月8日,
首批国家级旅游休闲街区名单公示,山东2地上榜根据中华人民共和国旅游行业标准旅游休闲街区等级划分(LBT0822021),按照文化和旅游部办公厅国家发展改革委办公厅关于开展国家级旅游休闲街区认定工作的通知安排,经评审,现将首批
现场白鹭翔集,密密麻麻飘飞如雪片,楼群成背景12月24日,顺德三字经公园白鹭成群,或栖息于树枝,或成群翱翔天空,为一片绿色植被带来生机。不远处的楼群灯火通明,人鸟和谐共处。白鹭是国家二级保护动物,享有环保鸟的美誉,只有空气质
乘坐西峰索道上华山周内人不多,决定去华山看看。乘景区旅行大巴从瓮峪盘旋而上,近一个小时到达华山西峰索道停车场。穿过太华胜景高大牌楼,沿着台阶继续向上,经过天威咫尺牌坊,就到了索道入口。天威咫尺意思是