如何为无超时遍历Drive的Google App Script添加文件复制功能
Google Apps Script 无超时遍历并复制文件夹文件改造方案
已有一段可无超时遍历指定根文件夹所有文件及子文件夹的Google Apps Script代码,需改造processFile函数,实现将遍历到的所有文件复制到目标文件夹。以下是具体改造方案:
改造步骤
- 新增目标文件夹配置:在入口函数中添加目标文件夹获取逻辑,并将其作为参数传递给遍历函数,确保后续处理能访问到目标位置。
- 传递目标文件夹参数:调整迭代处理函数,将目标文件夹参数传递到文件处理环节。
- 实现文件复制逻辑:替换原
processFile的日志输出,编写文件复制代码,提供两种复制方案供选择。
完整改造后代码
function main() { // 替换为你的源根文件夹ID var sourceRootFolder = DriveApp.getFolderById('替换为源文件夹ID'); // 替换为你的目标文件夹ID var targetRootFolder = DriveApp.getFolderById('替换为目标文件夹ID'); processRootFolder(sourceRootFolder, targetRootFolder); } function processRootFolder(rootFolder, targetFolder) { MAX_RUNNING_TIME_MS = 1 * 60 * 1000; var RECURSIVE_ITERATOR_KEY = "RECURSIVE_ITERATOR_KEY"; var startTime = (new Date()).getTime(); // [{folderName: String, fileIteratorContinuationToken: String?, folderIteratorContinuationToken: String}] var recursiveIterator = JSON.parse(PropertiesService.getDocumentProperties().getProperty(RECURSIVE_ITERATOR_KEY)); if (recursiveIterator !== null) { // 验证是否为同一文件夹 if (rootFolder.getName() !== recursiveIterator[0].folderName) { console.warn("检测到新文件夹,清除旧迭代器。"); recursiveIterator = null; } else { console.info("恢复之前的续跑会话。"); } } if (recursiveIterator === null) { console.info("启动新遍历会话。"); recursiveIterator = []; recursiveIterator.push(makeIterationFromFolder(rootFolder)); } while (recursiveIterator.length > 0) { recursiveIterator = nextIteration(recursiveIterator, targetFolder); var currTime = (new Date()).getTime(); var elapsedTimeInMS = currTime - startTime; var timeLimitExceeded = elapsedTimeInMS >= MAX_RUNNING_TIME_MS; if (timeLimitExceeded) { PropertiesService.getDocumentProperties().setProperty(RECURSIVE_ITERATOR_KEY, JSON.stringify(recursiveIterator)); console.info("已运行%d毫秒,达到时间限制,暂停执行,请再次运行脚本继续。", elapsedTimeInMS); return; } } console.info("遍历及复制完成"); PropertiesService.getDocumentProperties().deleteProperty(RECURSIVE_ITERATOR_KEY); } // 处理下一个文件或文件夹 function nextIteration(recursiveIterator, targetFolder) { var currentIteration = recursiveIterator[recursiveIterator.length - 1]; if (currentIteration.fileIteratorContinuationToken !== null) { var fileIterator = DriveApp.continueFileIterator(currentIteration.fileIteratorContinuationToken); if (fileIterator.hasNext()) { // 处理下一个文件 var path = recursiveIterator.map(function(iteration) { return iteration.folderName; }).join("/"); processFile(fileIterator.next(), path, targetFolder); currentIteration.fileIteratorContinuationToken = fileIterator.getContinuationToken(); recursiveIterator[recursiveIterator.length - 1] = currentIteration; return recursiveIterator; } else { // 文件处理完成 currentIteration.fileIteratorContinuationToken = null; recursiveIterator[recursiveIterator.length - 1] = currentIteration; return recursiveIterator; } } if (currentIteration.folderIteratorContinuationToken !== null) { var folderIterator = DriveApp.continueFolderIterator(currentIteration.folderIteratorContinuationToken); if (folderIterator.hasNext()) { // 处理下一个子文件夹 var folder = folderIterator.next(); recursiveIterator[recursiveIterator.length - 1].folderIteratorContinuationToken = folderIterator.getContinuationToken(); recursiveIterator.push(makeIterationFromFolder(folder)); return recursiveIterator; } else { // 子文件夹处理完成 recursiveIterator.pop(); return recursiveIterator; } } throw "程序逻辑错误,不应执行到此处"; } function makeIterationFromFolder(folder) { return { folderName: folder.getName(), fileIteratorContinuationToken: folder.getFiles().getContinuationToken(), folderIteratorContinuationToken: folder.getFolders().getContinuationToken() }; } // 方案A:直接复制所有文件到目标文件夹根目录 // function processFile(file, path, targetFolder) { // console.log("复制文件:" + path + "/" + file.getName()); // // 复制文件到目标文件夹,自动处理同名文件(添加"副本"后缀) // file.makeCopy(file.getName(), targetFolder); // } // 方案B:保持原目录结构,在目标文件夹创建对应子文件夹后复制 function processFile(file, path, targetFolder) { console.log("复制文件:" + path + "/" + file.getName()); // 根据原路径在目标文件夹创建对应子文件夹 var currentTargetFolder = targetFolder; var pathSegments = path.split("/"); // 遍历路径片段,逐层创建文件夹(如果不存在) for (var i = 0; i < pathSegments.length; i++) { var folderName = pathSegments[i]; var existingFolder = currentTargetFolder.getFoldersByName(folderName).next(); if (!existingFolder) { existingFolder = currentTargetFolder.createFolder(folderName); } currentTargetFolder = existingFolder; } // 复制文件到对应子文件夹 file.makeCopy(file.getName(), currentTargetFolder); }
注意事项
- 请替换代码中的
替换为源文件夹ID和替换为目标文件夹ID为实际的文件夹ID - 第一次运行脚本时,需要授权脚本访问Google Drive的权限
- 若目标文件夹存在同名文件,
makeCopy方法会自动添加"副本"后缀;如需覆盖或其他处理逻辑,可添加额外判断 - 原代码的超时续跑逻辑完全保留,当脚本达到运行时间限制暂停后,再次运行即可继续未完成的复制任务
内容的提问来源于stack exchange,提问作者OmarPoch
相关产品推荐
相关产品推荐

