4. IPFS目录与MFS:创建和管理目录、MFS(可变文件系统)的概念、使用MFS进行文件操作、目录的版本管理
好,我们继续深入IPFS的核心功能。前面我们聊了怎么把单个文件扔进IPFS网络,但实际项目中,你不可能只处理一个文件。一个完整的DApp,往往有成百上千个文件——HTML、CSS、JS、图片、配置文件……这时候,你就需要目录来组织它们了。
我个人习惯把IPFS的目录想象成一个「不可变的快照」。你创建了一个目录,它就是一个固定的CID。但问题来了——如果我想更新这个目录里的某个文件,怎么办?难道每次都要重新创建一个新目录?
嗯,这就是MFS(可变文件系统)要解决的问题。它让你像操作本地文件系统一样,去操作IPFS上的目录和文件。说白了,MFS就是给IPFS这个「只读」世界,加了一层「可写」的抽象。
4.1 创建和管理目录:从单文件到多文件
我们先从最基础的开始——怎么在IPFS里创建一个目录?
假设你有一个项目文件夹,里面包含 index.html 和 style.css。你想把它们一起添加到IPFS,并得到一个目录的CID。
最直接的方式,就是用 ipfs add 命令加上 -r 参数(递归添加):
# 创建一个测试目录
mkdir my-dapp
echo "<h1>Hello IPFS</h1>" > my-dapp/index.html
echo "body { color: red; }" > my-dapp/style.css
# 递归添加整个目录
ipfs add -r my-dapp/
# 输出类似:
# added Qm...style.css my-dapp/style.css
# added Qm...index.html my-dapp/index.html
# added Qm... my-dapp/
看到了吗?最后一行输出的CID,就是整个目录的哈希。你可以用这个CID,通过IPFS网关直接访问整个网站:http://localhost:8080/ipfs/<目录CID>。
ipfs add --cid-version=1 -r --hash=blake2b-256 来优化哈希算法。我在一个NFT元数据项目中用过这个,目录CID短了不少。
但这里有个坑——目录是不可变的。你修改了 index.html 的内容,重新添加,会得到一个全新的CID。原来的目录和文件依然存在于IPFS网络中(只要有人pin着)。
为什么会这样?因为IPFS的设计哲学就是「内容寻址」。内容变了,地址就必须变。这保证了数据的完整性,但也给「更新」带来了麻烦。
4.2 MFS(可变文件系统)的概念:给IPFS加一层「可写」抽象
MFS,全称Mutable File System,可变文件系统。它解决的核心问题就是:如何用一个固定的「路径」,指向不断变化的内容。
你可以把MFS想象成一个「指针」。这个指针指向一个IPFS目录的CID。当你更新MFS里的文件时,IPFS会在底层创建新的目录和文件(新的CID),然后自动更新这个指针。对外部用户来说,他们访问的路径始终不变,但内容已经更新了。
我记得第一次接触MFS时,觉得它有点像Git的「引用」(refs)。Git里,main 分支就是一个指针,指向最新的commit。MFS里的路径,比如 /my-site,也是一个指针,指向最新的目录CID。
MFS在IPFS节点内部维护了一个「根目录」。默认情况下,这个根目录是空的。你可以通过 /ipfs/ 路径访问不可变内容,通过 /ipfs/<CID> 访问特定版本,而MFS则提供了一个 /mfs/ 的抽象层。
- 不可变层:
/ipfs/<CID>— 内容一旦创建,永不改变 - 可变层:
/mfs/<path>— 路径不变,内容可以更新 - 底层机制: MFS每次写入都会创建新的IPFS对象,然后更新内部指针
4.3 使用MFS进行文件操作:像操作本地文件一样
好,理论说完了,我们上手操作。MFS提供了一组类似Unix命令的API:files 子命令。
4.3.1 基本操作:cp、mkdir、stat
首先,确保你的IPFS节点在运行。然后,我们创建一个MFS目录:
# 在MFS根目录下创建一个名为 "my-site" 的目录
ipfs files mkdir /my-site
# 查看MFS根目录的内容
ipfs files ls /
# 输出:my-site
现在,我们把本地文件复制到MFS中:
# 把本地文件复制到MFS
ipfs files cp /ipfs/<index.html的CID> /my-site/index.html
# 或者,直接用标准输入写入
echo "<h1>Updated</h1>" | ipfs files write /my-site/index.html
# 查看MFS目录的状态
ipfs files stat /my-site
# 输出类似:
# Qm... (目录的CID)
# Size: 1234
# CumulativeSize: 5678
# Type: directory
这里有个关键点:ipfs files cp 是从IPFS的不可变层复制到MFS的可变层。而 ipfs files write 是直接写入内容到MFS路径。
ipfs files write 覆盖了一个正在被多个服务引用的MFS文件。结果导致部分服务读取到了旧版本,部分读取到了新版本。后来我养成了习惯:更新MFS文件前,先确认没有其他进程在读取它。或者,用版本号路径来隔离。
4.3.2 读取和删除
# 读取MFS文件内容
ipfs files read /my-site/index.html
# 删除MFS文件
ipfs files rm /my-site/index.html
# 删除整个目录(递归)
ipfs files rm -r /my-site
嗯,是不是感觉跟Linux命令很像?这就是MFS的设计初衷——降低学习成本。
4.4 目录的版本管理:用MFS实现「伪版本控制」
MFS本身不提供像Git那样的版本历史。但我们可以利用IPFS的不可变特性,手动实现版本管理。
思路很简单:每次更新MFS目录前,先把当前版本的CID记录下来。这样,你就有了一个「版本链」。
4.4.1 手动版本管理
# 1. 查看当前MFS目录的CID
ipfs files stat /my-site
# 输出:QmVersion1...
# 2. 把这个CID保存到某个地方(比如一个文本文件)
echo "QmVersion1..." >> versions.txt
# 3. 更新MFS目录
echo "<h1>Version 2</h1>" | ipfs files write /my-site/index.html
# 4. 查看新CID
ipfs files stat /my-site
# 输出:QmVersion2...
# 5. 再次保存
echo "QmVersion2..." >> versions.txt
这样,你就有了一个版本列表。想回滚到旧版本?直接用 ipfs files cp 把旧版本的CID复制回来:
# 回滚到版本1
ipfs files cp /ipfs/QmVersion1... /my-site
4.4.2 使用IPFS的「Pin」来保护版本
别忘了,IPFS里的内容需要被「Pin」才能持久保存。如果你更新了MFS目录,旧版本的文件如果没有被Pin,可能会被垃圾回收掉。
# 在更新前,先Pin住旧版本
ipfs pin add QmVersion1...
# 然后更新MFS
# ... 更新操作 ...
# 这样,旧版本就安全了
ipfs pin ls | grep QmVersion1
我个人习惯写一个脚本,每次更新MFS时自动执行:stat -> pin -> update -> stat -> pin。这样就不会漏掉任何版本。
4.5 实战:用MFS部署一个可更新的静态网站
最后,我们串起来做一个完整示例。假设你要部署一个个人网站,并且希望每次更新后,用户都能通过同一个URL访问到最新内容。
#!/bin/bash
# deploy.sh - 部署脚本
SITE_NAME="my-blog"
LOCAL_DIR="./dist"
# 1. 构建网站(假设你用的是静态站点生成器)
echo "Building site..."
# npm run build # 实际项目中取消注释
# 2. 添加本地文件到IPFS,获取目录CID
echo "Adding to IPFS..."
SITE_CID=$(ipfs add -r -Q $LOCAL_DIR)
echo "New site CID: $SITE_CID"
# 3. 如果MFS中还没有这个站点,先创建目录
ipfs files stat /$SITE_NAME 2>/dev/null || ipfs files mkdir /$SITE_NAME
# 4. 获取旧版本CID并Pin住
OLD_CID=$(ipfs files stat /$SITE_NAME | head -1)
if [ ! -z "$OLD_CID" ]; then
echo "Pinning old version: $OLD_CID"
ipfs pin add $OLD_CID
fi
# 5. 更新MFS目录
echo "Updating MFS..."
ipfs files cp /ipfs/$SITE_CID /$SITE_NAME
# 6. 输出最终访问地址
echo "Site updated!"
echo "Access via: http://localhost:8080/ipfs/$SITE_CID"
echo "Or via MFS: http://localhost:8080/ipfs/$(ipfs files stat /$SITE_NAME | head -1)"
这个脚本做了几件事:
- 构建本地网站
- 添加到IPFS获取新CID
- Pin住旧版本(防止丢失)
- 更新MFS路径指向新版本
你想想看,用户只需要记住你的MFS路径(比如 /my-blog),每次访问都是最新内容。而旧版本都被Pin住了,随时可以回滚。
- IPFS目录 是不可变的,适合存储静态资源
- MFS 提供了可变层,让你用固定路径访问更新内容
- 版本管理 需要手动实现,核心思路是「更新前先Pin旧版本」
- 实战中,MFS + Pin + 脚本,可以构建出生产级别的可更新去中心化应用
嗯,这一章的内容就到这里。下一章我们会聊IPFS的「内容路由」和「DHT」——说白了,就是你的文件是怎么被找到的。到时候见。