Oasis's Cloud

一个人的首要责任,就是要有雄心。雄心是一种高尚的激情,它可以采取多种合理的形式。
—— 《一个数学家的辩白》

文件备份


如何唯一标识文件

这要求哈希函数满足 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/