可变文件系统(MFS)允许您像使用传统的基于名称的文件系统一样,使用文件和目录。
Lesson 1 IPFS简介
IPFS: 星际文件系统
IPFS,或着称为星际文件系统,是用于在去中心化网络上共享数据的对等(P2P)网络协议。 顾名思义,你可以将IPFS视为文件系统,它具有一些独特的特性,使其成为安全的,去中心化共享的理想选择。
如果你还没有接触过,我们建议你浏览我们的去中心化数据结构教程,你可以在其中了解去中心化网络的所有信息,以及它与你熟悉的传统网络之间的区别。 在那里,你将学习有关内容寻址,加密哈希,内容标识符(CID)以及在节点间共享信息的所有内容,为了更好的理解本教程,所有这些概念都是你需要了解的。
在IPFS中存储和共享数据
当内容被添加到IPFS网络时,内容将会被保存在哪里?
作为点对点数据存储系统,IPFS允许每个用户(节点)在本地托管任何他们喜欢的数据。 当你第一次向IPFS添加内容时,实际上只是将内容通过IPFS协议转换成共享格式,存储在本地设备上。 通常,我们是在自己的计算机上安装IPFS,并创建一个新的IPFS实例(也称为节点)。 这就是你的数据在本地保存的地方,并通过内容标识符(CID)引用。 存储在IPFS中的数据可以采用多种形式,但最常见的使用场景之一,是对传统文件的共享,我们将在本教程中详细了解。
当你联网时,你可以选择与其他节点共享你的数据或文件,但如果你是唯一一个托管该资源的人,则当你的计算机离线时,其他节点将无法使用该资源。 让多个节点托管相同的文件可使资源更获得更高的可用性,并且CID(通过cryptograhpic哈希创建的唯一内容标识符)的使用也保证了系统安全。 我们将在未来的教程中详细讨论共享,但是现在我们将专注于如何在你自己的IPFS实例中处理文件。
可变文件系统(Mutable File System)
因为IPFS中的文件是内容寻址并且无法篡改的,所以你无法编辑文件; 因此,每次更改都会创建一个新文件。 可变文件系统(MFS)是一个内置于IPFS中的工具,可以让你像在基于名称的文件系统中一样处理文件 - 你可以添加,删除,移动和编辑MFS文件,并自动帮你完成更新链接和创建哈希的所有工作。 它是一种抽象概念,可以让你像处理可变数据一样,处理不可变数据。
可以通过调用IPFS CLI(命令行界面)和API中的files命令访问MFS。 在本教程中,我们将探索Files API。
如果你之前使用过命令行中的文件和目录,那么许多MFS方法看起来都因该非常熟悉!
让我们开始探索如何使用IPFS中的文件!
Lesson 2 查看目录状态
使用ProtoSchool中的文件
在我们的ProtoSchool教程中,当你每次点击课程中的“提交”按钮时,我们都会在浏览器中为您创建一个新的IPFS节点。 每当你在我们的课程中看到ipfs.someMethod()时,ipfs就是一个引用你的IPFS实例的变量,也称为节点。 你执行的操作仅影响你自己的IPFS节点,而不影响属于你的peers上的节点。
我们正在后台创建你的IPFS节点,以便你可以专注于我们的课程,但最终你需要学会安装IPFS并在终端中运行程序来启动你自己的本地节点。 当你准备好进行实验时,可以在我们的文档中找到有关安装IPFS和初始化节点的说明文档。
如前所述,与可变文件系统相关的方法是Files API的一部分,因此它们将采用ipfs.files.someMethod()的格式。 让我们看一下即使在将任何文件添加到IPFS节点之前也可以开始使用的简单方法。
使用ipfs.files.stat探索IPFS节点
使用IPFS节点时,通常需要检查文件或目录的状态。 您可以使用ipfs.files.stat执行此操作,传入你要查看的路径。
例如,要查看位于根目录(/)中的名为stuff的目录的状态,我们可以像这样调用方法:
await ipfs.files.stat('/stuff')
此方法返回一个包含有关我们的文件或目录的基本数据的对象:
- hash(带有加密哈希的字符串)
- size(文件或目录大小,以字节为单位的整数)
- cumulativeSize(以字节为单位构成DAGNodes文件的整数大小)
- type(可以是目录或文件的字符串)
- blocks(如果type是目录,这是目录中的文件数;如果type是文件,则是组成文件的块数)
- withLocality(一个布尔值,表示是否存在位置信息)
- local(一个布尔值,表示查询的dag是否完全存在于本地)
- sizeLocal(一个整数,表示本地存在的数据的累计大小)
注意!目录的size始终为0,无论它包含多少条目,因为目录实际上只是一组指向其他文件和目录的链接。相反,目录的cumulativeSize会随着目录内容的变化而变化。它不仅代表该目录中所有条目的文件大小,还代表描述这些条目的元数据:类型,块大小等。
需要注意的是,即使你的IPFS节点还没有任何内容,也可以用stat对它进行查看。即使是空节点也有CID(哈希)。
Lesson 3 使用ProtoSchool中的文件
出于安全考虑,Web浏览器不允许我们直接更改计算机文件系统中的文件。 因此,你需要将一个或多个文件上传到本教程中使用的浏览器。
在每个练习中,你会发现可以通过拖放或从文件资源管理器中选择文件来上传文件。 如果仔细查看代码编辑器中的run函数,你会发现它现在需要一个参数files。 当您从计算机上传文件时,我们必须确保它们作为文件数组传递给函数。 只要你不刷新浏览器,这些文件将在本教程的下一课中保持可访问状态,但你也可以选择上传不同的文件以供每节课使用。
练习准备工作,请从你的计算机上传一个或多个文件,并查看浏览器收到的文件数组。
Lesson 4 将文件添加到MFS
现在我们可以在浏览器中访问文件,让我们看看如何将它们添加到IPFS中。
要将文件添加到IPFS,我们可以使用MFS files.write方法,如下所示:
await ipfs.files.write(path, content, [options])
MFS的 files.write方法可以接受Buffer,ReadableStream,PullStream,Blob(仅在浏览器中)或string path(仅在Node.js中)形式的文件。浏览器中的文件对象是一种Blob格式,我们继续!
即使浏览器中的文件对象碰巧知道自己的文件名,Blob通常也不知道,因此IPFS无法直接确定真实的文件名。我们必须提供所需的文件名作为path的一部分。
path是你要在IPFS实例中创建的新路径,包括所需的文件名。 (请注意,它是我们描述的目标路径,而不是文件已经保存在你的计算机上的路径。)
MFS files.write方法与你在自己的计算机上使用的方法类似,实际上是为编辑现有文件的内容而构建的。不过,如果在给定的路径不存在这个文件,我们也可以通过一个布尔类型的选项{create : true}来创建一个全新的文件。
因此,如果我们的浏览器中有一个文件对象,可通过变量catPic访问,并且我们想将它添加到IPFS上的根目录并将其命名为cat.jpg,我们可以这样做:
await ipfs.files.write('/cat.jpg', catPic, { create : true })
如果有必要,我们可以使用拼接字符串(将字符串连接在一起)的方式来创建相同的路径。 如果你的文件名是文件对象的属性,这种方法在浏览器中使用就很方便。
await ipfs.files.write('/' + catPic.name, catPic, { create : true })
请注意,files.write方法不提供返回值。
稍后我们将介绍如何将文件添加到根目录以外的目录。
Lesson 5 查看目录的内容
当我们使用files.write向MFS添加文件时,该方法没有返回任何值,但我们仍然可以检查以确保一切按预期工作。
在Mutable File System中,我们可以使用files.ls方法检查目录。 如果你曾使用命令行列出计算机上目录的内容,那么对这种方法应该会非常熟悉。
file.ls方法如下所示:
await ipfs.files.ls([path], [options])
该方法默认列出根目录(/)的内容,或者你可以选择指定要检查的特定path(目录),例如/ catPics,
file.ls生成一个对象数组,你正在查看的目录中的每个文件或目录,具有以下属性:
- name(默认值):文件名
- type({long : true} 可选项):对象的类型(0 -文件 或 1 - 目录)
- size({long : true} 可选项):文件的大小(以字节为单位)
- hash({long : true} 可选项):表示IPFS文件的加密哈希或内容标识符(CID)
注意!要返回所有这些属性的值,必须使用选项{long : true}。 否则,除名称字段外的所有属性都将返回为0(对于size和type)或""(对于hash)
如果我们想查看 /catPics 目录下所有内容的详细信息,我们可以这样做:
await ipfs.files.ls('/catPics', { long : true })
你可以在files.ls API文档中了解有关其他选项的更多信息。
Lesson 6 了解CID如何随着数据的变化而变化
正如你在去中心化数据结构教程中所了解到的,CID(内容标识符)与它们通过加密哈希表示的内容一一对应。 具有相同内容的两个文件具有相同的CID(哈希),并且就算只有一点点差异的两个文件,都具有不同的CID。 目录也是如此。 每次更新文件或目录的内容时,其CID都会更改。
当你的根目录为空并且使用ipfs.files.stat检查其状态时,你会看到以下结果:
{
"hash": "QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn",
"size": 0,
"cumulativeSize": 4,
"blocks": 0,
"type": "directory",
"withLocality": false
}
你现在添加了一个或多个文件会是什么样子? 哪些字段现在应该更改?
Lesson 7 创建一个目录
我们已经学会了如何将文件添加到根目录,但是我们如何创建一个新目录呢? 同样的,这与你在自己计算机上使用命令行的过程非常相似。
MFS的files.mkdir方法在指定路径创建新目录。 例如,要将一个叫images目录添加到根目录(/),我们可以这样做:
await ipfs.files.mkdir('/images')
可选项parents(默认为false)指定了在给定的路径中,如果有父目录不存在的情况,是否要创建该父目录。 这在上面的例子中不需要,因为新的images目录是现有目录(/)的直接子目录。 但是,如果我们想要创建一个还不存在的新目录,我们需要将parent的值显式设置为true,如下所示:
await ipfs.files.mkdir('/my/beautiful/images', { parents : true })
注意!虽然创建不存在路径的方法是类似的,但请注意我们使用files.mkdir的{parents : true}选项,而不是files.write提供的{create : true}选项。
Lesson 8 移动文件或目录
MFS允许你使用files.mv方法在目录之间移动文件,就像在本地计算机上一样。
该方法如下所示:
await ipfs.files.mv(...from, to, [options])
from是你要移动的内容的源路径(或路径)。 to是目标路径。
如果目标路径引用了尚不存在的上级路径,则需要使用{parents : true}选项,就像使用files.mkdir一样。
你可以使用files.mv执行许多不同的操作:
// move a single file into a directory
await ipfs.files.mv('/source-file.txt', '/destination-directory')
// move multiple files into a directory (note the two acceptable formats)
await ipfs.files.mv('/source-file-1.txt', '/source-file-2.txt', '/destination-directory')
await ipfs.files.mv(['/source-file-1.txt', '/source-file-2.txt'], '/destination-directory')
// move a directory into another directory
await ipfs.files.mv('/source-directory', '/destination-directory')
// overwrite the contents of a destination file with the contents of a source file
await ipfs.files.mv('/source-file.txt', '/destination-file.txt')
Lesson 9 复制文件或目录
与files.mv不同,files.mv在将项目移动到其目标路径后删除其源路径中的项目,files.cp方法允许你将文件或目录复制到新位置,同时保留源位置的项目。
该方法如下所示:
await ipfs.files.mv(...from, to, [options])
from是你要移动的内容的源路径(或路径)。 to是目标路径。
如果目标路径引用了尚不存在的父目录,则需要使用{parents : true}选项,就像使用files.mkdir一样。
你可以使用files.mv执行许多不同的操作:
// move a single file into a directory
await ipfs.files.mv('/source-file.txt', '/destination-directory')
// move multiple files into a directory (note the two acceptable formats)
await ipfs.files.mv('/source-file-1.txt', '/source-file-2.txt', '/destination-directory')
await ipfs.files.mv(['/source-file-1.txt', '/source-file-2.txt'], '/destination-directory')
// move a directory into another directory
await ipfs.files.mv('/source-directory', '/destination-directory')
// overwrite the contents of a destination file with the contents of a source file
await ipfs.files.mv('/source-file.txt', '/destination-file.txt')
Lesson 10 浏览文件的内容
MFS有一个files.read方法,允许你在缓存中显示文件的内容。 这使我们可以轻松读取.txt文件的内容。
该方法采用以下格式:
await ipfs.files.read(path, [options])
path是要读取的文件的路径,它必须指向文件而不是目录。
files.read方法返回一个Buffer,可以使用 toString('utf8') 方法将其转换为字符串。 例如:
let bufferedContents = await ipfs.files.read('/directory/some-file.txt') // a buffer
let contents = bufferedContents.toString('utf8') // a string
或者
let contents = (await ipfs.files.read('/directory/some-file.txt')).toString('utf8') // a string
// notice the parentheses around the entire await statement
当你准备在真机上尝试此操作时,你需要注意files.read方法可能会因为读取的文件太大,从而导致大量内存被占用。 你可能希望通过files.readReadableStream或files.readPullStream方法来进行进行文件内容的浏览。
Lession 11 删除文件或目录
MFS允许您使用files.rm方法删除文件或目录:
await ipfs.files.rm(...paths, [options])
paths是要删除的一个或多个路径。
默认情况下,如果你尝试删除非空目录,则将导致操作失败。 要删除目录及其中包含的所有内容,你需要使用{recursive : true}选项。
// remove a file
await ipfs.files.rm('/my/beautiful/file.txt')
// remove multiple files (note the two acceptable formats with or without [ ])
await ipfs.files.rm('/my/beautiful/file.txt', '/my/other/file.txt')
await ipfs.files.rm(['/my/beautiful/file.txt', '/my/other/file.txt'])
// remove a directory and its contents
await ipfs.files.rm('/my/beautiful/directory', { recursive: true })
// remove a directory only if it is empty
await ipfs.files.rm('/my/beautiful/directory')
网友评论