文件备份
如何唯一标识文件
- 根据文件内容进行比较,逐字节比较的算法太慢
- 好一点的做法是给文件生成一个 哈希串,通过比较 哈希串
这要求哈希函数满足 2 点特性: - 输出取决于整个输入,即使改变单个字节也会生成不同的哈希码 - 输出看起来像随机数,且不可预测,分布均匀
我们对文件计算 160位 SHA-1 哈希值。我们不需要复杂的算法,我们需要的是极小的碰撞。
为什么选择 SHA-1?
首先我们的目标是极小的碰撞,那么我们要知道所要加密文件会出现碰撞的机率是怎么样的。这里例举了生日问题
两个人同一天生日的机率是 1/365(忽略 2月29日)。因此不是同一天生日的机率是 364/365。 当我们添加第三个人时,第三人与前两个人不重复的机率是 363/365,所以没有人生日相同的总体机率是 (365/365) * (364/365) * (363/365)。按照此公式进行计算,在 23 人的团体中,两人生日相同的概率为 50%,当人数上升到 70人,这一概率为 99.9%
可以通过上面的算法,计算得出 50% 碰撞机率,我们需要散列多少文件,我们不使用 365,而是使用 2 的 160次方。
为什么不实用 MD5,因为 SHA-1 采用的长度比 MD5 多 32 位。MD5 出现碰撞的机率相对于 SHA-1 更高。
流应该怎么使用?
在 Node.js 中,可以使用 crypto 模块。为了不阻塞的执行,我们可以采用流处理。
流处理 API 是说 一次处理一个块的数据,而不是要求所有数据一次都在内存中。Nodejs 中数据流块的大小可以配置的,比如 可写流可以设置 highWaterMark(默认值:16384,16KiB)。
比如每次读取 16KB 的话,我们应该如何处理这些数据呢,比如基于流查找字符。在 Nodejs 中提供了 readline 模块,可以按照行的方式读取。
const fs = require('fs')
const readline = require('readline')
const stream = require('stream')
const searchStream = (filename, text) => {
return new Promise((reslove) => {
const inStream = fs.createReadStream(`file/${filename}.txt`)
const outStream = new Stream
const rl = readline.createInterface(inStream, outStream)
const result = []
const reg = new RegExp(text, "i")
rl.on('line', (line) => {
if(line && line.search(reg) >= 0) {
reslut.push(line)
}
})
rl.on('close', () => {
console.log(`finished search: ${filename}`)
reslove(result)
})
})
}
searchStream('demo', 'Hi')
如何备份文件
很多文件在创建之后很少改动,如果每次改动,我们保存整个项目的快照这是很糟的,为什么? - 用户并不是改了所有文件,我们应该只记录改动的文件 - 快照整个项目的文件,会造成存储的浪费 为了避免上面两个问题,我们可以通过将 Hash 作为 Key,保存改动的文件。 例如: a.file 改动了,我们给 a.file 计算 Hash 值,Hash 结果为 abcd1234,我们用这个结果作为 备份文件的名字 abcd1234.back
管理备份文件
既然我们针对每个改动的文件生成了本分文件,我们就要追踪备份文件,例如:a.file 连续发生了3次改动,怎么知道哪个备份文件是最新的呢?
可以通过提交次数创建目录,里面保存着每个备份版本。
Git 是如何实现文件管理的?
https://wyag.thb.lt/