硬盘坏了,一气之下写了个康复程序
师傅解救无望
硬盘现已寄过去超过一周了,一问竟然是还没开端弄
???
再过一周,上来就问我分几个区?我要康复哪些数据?我要康复的数据在哪个位置?
那好吧,已然给了钱师傅也都抛弃了,我也没什么好寄托期望的了。何况通过这三个星期的缓解,心境现已平复了许多,就像时光,回不来了便是回不来了。
自救之路
在把硬盘寄过去的时刻里,等待师傅的修正成果的时刻里,我并没有闲着(在摸鱼)。
通过调研,数据康复办法一般有:
- 硬件损坏,对坏的盘进行修正
- 误删或逻辑过错等,文件扫描修正
- git 重置康复
很明显,这些都不适用于我现在的场景。由于师傅能不能修好是不知道的,我仅仅数据盘没了,体系盘还在。由于 vscode 的数据目录空间占比较小,就没有搬迁到数据盘里,这刚好可认为康复代码供给了可能。
这是由于新版 vscode 有一个时刻线
功用,这个时刻线数据是默认存储在用户目录下的。
我从 C:/Users/love/AppData/Roaming/Code/User/History
目录中确实找到了许多名为 entries.json 的文件,结构如下:
{
// 配置版别
"version": 1,
// 本来文件所在位置
"resource": "file:///d%3A/git2/cloudcmd/.madrun.mjs",
// 文件历史
"entries": [
{
// 历史文件存储的名称
"id": "YFRn.mjs",
"source": "作业区修改",
// 修改的时刻
"timestamp": 1656583915880
},
{
"id": "Vfen.mjs",
"timestamp": 1656585664751
},
]
}
通过上面的文件大概能够看到,每一个时刻点的文件都保存在另一个随机命名的文件里。而网上的办法基本都是自己一个个手动到目录里去依据最新的 id 去找对应的文件内容,然后创立文件并把内容复制出来。
这个进程康复一两个文件还好,但我这可是要康复整个 git 作业区,大概有几十个项目上千个文件。
这时候当然是在网上找找有没有什么 vscode 数据康复
相关的东西,很惋惜找了大半天都没有找到。
气死我了,一气之下就自己写个!
康复程序开发步骤
毕竟只要数据在磁盘上,无非便是一个文件读取操作的问题,还要拿在这水文章,见谅见谅。
首先考虑需求:
- 我要完成一个主动扫描 vscode 数据目录
- 然后以原始的目录结构复原出来,不需求我自己去创立文件夹和文件
- 假如复原的文件最新的那份不是我想要的,我还能依据时刻线进行比照和挑选
- 扫描出来有N个项目时,我能够指定只复原某此项目
- 我能够搜索文件、目录名或文件内容进行复原
- 为了便利,我还要一个看起来不太丑的操作界面
大概就上面这些吧。
然后考虑完成:
我要完成一个主动扫描 vscode 数据目录
要的便是我自己连数据目录和康复地址也不需求填写,就能主动康复的那种。那么就让程序来主动查找数据目录。通过调研,各版别的 vscode 的数据目录一般保存在这些当地:
参考: stackoverflow.com/a/72610691
- win -- C:\Users\Mark\AppData\Roaming\Code\User\History
- win -- C:\Users\Mark\AppData\Roaming\Code - Insiders\User\History
- /home/USER/.config/VSCodium/User/History/
- C:\Users\USER\AppData\Roaming\VSCodium\User\History
大概有上面这些途径,当然不排除运用者故意把默认位置修改掉这种边际情况,或许运用者就只想扫描某个数据目录的情况,所以我也要支撑手动输入目录:
let { historyPath, toDir } = req.body
const homeDir = os.userInfo().homedir
const pathList = [
historyPath,
`${homeDir}/AppData/Roaming/Code/User/History/`,
`${homeDir}/AppData/Roaming/Code - Insiders/User/History/`,
`${homeDir}/AppData/Roaming/VSCodium/User/History`,
`${homeDir}/.config/VSCodium/User/History/`,
]
historyPath = (() => {
return pathList.find((path) => path && fs.existsSync(path))
})()
toDir = toDir || normalize(`${process.cwd()}/re-store/`)
然后以原始的目录结构复原出来……
这就需求解析扫描到的时刻线文件 entries.json
了。咱们先把解析成果放到一个 list 中,以下是一个完好的解析办法。
然后再把列表转换为树型,与硬盘上的状态对应起来,这样便于调试数据和可视化。
function scan({ historyPath, toDir } = {}) {
const gitRoot = `${historyPath}/**/entries.json`
fs.existsSync(toDir) === false && fs.mkdirSync(toDir, { recursive: true })
const globbyList = globby.sync([gitRoot], {})
let fileList = globbyList.map((file) => {
const data = require(file)
const dir = path.parse(file).dir
// entries.json 地址
data.from = file
data.fromDir = dir
// 原文件地址
data.resource = decodeURIComponent(data.resource).replace(
/.*?\/\/\/(.*$)/,
`$1`
)
// 原文件存储目录
data.resourceDir = path.parse(data.resource).dir
// 康复后的完好地址
data.rresource = `${toDir}/${data.resource.replace(/:\//g, `/`)}`
// 康复后的目录
data.rresourceDir = `${toDir}/${path
.parse(data.resource)
.dir.replace(/:\//g, `/`)}`
const newItem = [...data.entries].pop()
// 创立文件所在目录
fs.mkdirSync(data.rresourceDir, { recursive: true })
const binary = fs.readFileSync(`${dir}/${newItem.id}`, {
encoding: `binary`,
})
fs.writeFileSync(data.rresource, binary, { encoding: `binary` })
return data
})
const tree = pathToTree(fileList, { key: `resource` })
return tree
}
为了便利,我还要一个看起来不太丑的操作界面
咱们要把文件树的形式展示出来,还要便利切换。后边决定运用 macos 的文件管理器风格,大概如下。
假如复原的文件最新的那份不是我想要的,我还能依据时刻线进行比照和挑选
理论上这里应该要做一个像 vscode 比照文件那样,有代码高亮功用,并且把有差异的字符高亮出来。
实际上,这个需求得加钱。
由于界面是在浏览器里的,需求主动打开,浏览器与体系交互需求一个接口,所以咱们运用 opener
来主动打开浏览器。
运用 get-port
来主动生成接口服务的端口,防止运用时呈现占用。
const opener = require(`opener`)
const { portNumbers, default: getPort } = await import(`get-port`)
const port = await getPort({ port: portNumbers(3000, 3100) })
const server = express()
server.listen(port, `0.0.0.0`, () => {
const link = `http://127.0.0.1:${port}`
opener(link)
})
封装成东西,我为人人
理论上我底子不需求什么 UI 界面,也不需求配置,由于我的文件都康复出来了我还花时刻去搞毛线?
实际上,如果别人也有这个康复文件的需求呢?那么他只要
运行下面这条指令代码就能立刻
康复到当时目录啦!
npx vscode-file-recovery
这便是康复后的文件在硬盘里的姿态啦:
一切代码位于:
- github github.com/wll8/vscode…
建议保藏,以备不时之需。/手动狗头