Google Drive批量恢复文件版本遇脚本超时,求断点续传方案
Google Apps Script 断点续传实现方案
核心思路
- 用Google脚本自带的**脚本属性(ScriptProperties)**存储执行进度,比如已处理的文件夹ID、文件ID列表、当前处理位置;文件量极大时,也可以在Drive根目录建个隐藏JSON文件存进度
- 脚本启动先读进度,有断点就从断点续跑,没断点就从根目录开始
- 主动监控运行时间,接近28分钟(留2分钟余量)时保存进度并终止,下次启动自动续传
具体实现步骤
1. 进度存储与读取
脚本启动时先检查有没有保存的进度:
- 读
ScriptProperties里的lastProcessedFolderId(最后处理的文件夹ID)、processedFileIds(已处理文件ID列表)、currentFileIndex(当前处理到的文件索引) - 没进度就从根文件夹开始;有进度就从指定位置继续
2. 处理过程中实时更新进度
- 每处理完一个文件就更新进度到
ScriptProperties,批量处理时也可以每20个文件存一次,避免频繁写入拖慢速度 - 递归遍历文件夹时,同步记录当前所在的文件夹ID,确保断点能精准回到对应目录
3. 超时检测与主动终止
在循环里加运行时间判断:
- 记录脚本启动时间
startTime - 每次循环算已运行时长,到28分钟就保存进度并终止,留足时间完成进度写入
代码示例
function batchRestoreFiles() { // 读取断点进度 const props = PropertiesService.getScriptProperties(); const lastFolderId = props.getProperty('lastProcessedFolderId'); const processedFiles = props.getProperty('processedFileIds') ? JSON.parse(props.getProperty('processedFileIds')) : []; const currentIndex = parseInt(props.getProperty('currentFileIndex')) || 0; const attackDate = new Date('2024-05-01'); // 替换成你的勒索攻击日期 // 确定起始文件夹 let startFolder = lastFolderId ? DriveApp.getFolderById(lastFolderId) : DriveApp.getRootFolder(); const startTime = new Date().getTime(); const maxRunTime = 28 * 60 * 1000; // 28分钟超时阈值 // 获取当前文件夹及子文件夹的所有文件 const allFiles = getAllFiles(startFolder); // 跳过已处理的文件 const remainingFiles = allFiles.slice(currentIndex); for (let i = 0; i < remainingFiles.length; i++) { const file = remainingFiles[i]; const fileId = file.getId(); // 跳过已经处理过的文件 if (processedFiles.includes(fileId)) continue; // 执行文件恢复逻辑(替换成你原来的处理代码) restoreTargetFile(file, attackDate); // 更新进度到脚本属性 processedFiles.push(fileId); props.setProperty('processedFileIds', JSON.stringify(processedFiles)); props.setProperty('currentFileIndex', currentIndex + i + 1); props.setProperty('lastProcessedFolderId', file.getParents().next().getId()); // 检测是否接近超时 const elapsed = new Date().getTime() - startTime; if (elapsed >= maxRunTime) { console.log('即将超时,保存进度后终止'); return; } } // 全部处理完成,清空进度记录 props.deleteAllProperties(); console.log('所有文件处理完毕'); } // 递归获取文件夹下所有文件(包含子文件夹) function getAllFiles(folder) { let files = folder.getFiles(); let result = []; while (files.hasNext()) { result.push(files.next()); } let subFolders = folder.getFolders(); while (subFolders.hasNext()) { result = result.concat(getAllFiles(subFolders.next())); } return result; } // 单个文件恢复逻辑:还原攻击前版本、修正文件名和修改时间 function restoreTargetFile(file, attackDate) { const versions = file.getVersions(); let validVersion = null; // 找到攻击日期前的最后一个有效版本 for (let version of versions) { if (version.getLastUpdated() < attackDate) { validVersion = version; break; } } if (validVersion) { // 恢复版本 validVersion.restore(); // 还原文件修改时间 file.setLastUpdated(validVersion.getLastUpdated()); } } // 续传直接调用主函数即可,无需额外写逻辑 function resumeRestore() { batchRestoreFiles(); }
额外建议
- 直接运行
batchRestoreFiles就行,它会自动判断是否续传 - 可以给脚本加个定时触发器(比如每30分钟跑一次),实现自动续传直到所有文件处理完
- 如果文件量特别大,把进度存在Drive的隐藏JSON文件里,避免
ScriptProperties的存储上限不够用
内容的提问来源于stack exchange,提问作者Antonio
相关产品推荐
相关产品推荐

