我正在电子表格中编写Google Apps脚本。我的用例包括迭代一组给定的子文件夹。问题是处理时间超过了Google允许的最长时间(6分钟),因此我必须对脚本进行编程才能以后恢复。我正在创建一个触发器来恢复任务,但这不是我问题的一部分(至少,目前不是更重要的一个)。
我的代码看起来像这样(减少到最低限度来说明我的问题):
function launchProcess() {
var scriptProperties = PropertiesService.getScriptProperties();
scriptProperties.setProperty(SOURCE_PARENT_FOLDER_KEY, SOURCE_PARENT_FOLDER_ID);
scriptProperties.deleteProperty(CONTINUATION_TOKEN_KEY);
continueProcess();
}
function continueProcess() {
try {
var startTime = (new Date()).getTime();
var scriptProperties = PropertiesService.getScriptProperties();
var srcParentFolderId = scriptProperties.getProperty(SOURCE_PARENT_FOLDER_KEY);
var continuationToken = scriptProperties.getProperty(CONTINUATION_TOKEN_KEY);
var iterator = continuationToken == null ? DriveApp.getFolderById(srcParentFolderId).getFolders() : DriveApp.continueFolderIterator(continuationToken);
var timeLimitIsNear = false;
var currTime;
while (iterator.hasNext() && !timeLimitIsNear) {
var folder = iterator.next();
processFolder_(folder);
currTime = (new Date()).getTime();
timeLimitIsNear = (currTime - startTime >= MAX_RUNNING_TIME);
}
if (!iterator.hasNext()) {
scriptProperties.deleteProperty(CONTINUATION_TOKEN_KEY);
} else {
var contToken = iterator.getContinuationToken();
scriptProperties.setProperty(CONTINUATION_TOKEN_KEY, contToken);
}
} catch (e) {
//sends a mail with the error
}
}
当调用launchProcess时,它只为另一个迭代文件夹的方法continueProcess准备程序。迭代器是通过使用延续令牌获得的,当它存在时(它不会出现在第一次调用中)。当时间限制接近时,continueProcess获取延续令牌,将其保存在属性中并等待下一次调用。
我遇到的问题是迭代器总是返回同一组文件夹,尽管它是由不同的标记构建的(我已经打印过它们,所以我知道它们是不同的)。
关于我做错了什么的任何想法?
提前谢谢。
答案 0 :(得分:2)
看来你的循环没有正确构建。 (编辑:实际上,可能还有关于我们如何打破while循环的另一个问题,请参阅我在评论中对此的看法)
另请注意,在此上下文中使用try / catch没有特殊原因,因为我认为没有理由hasNext()
方法会返回错误(但如果您认为这样,您可以随时添加它)< / p>
这是一个有效的示例,我添加了触发器创建/删除行来实现我的测试。
var SOURCE_PARENT_FOLDER_ID = '0B3qSFd3iikE3MS0yMzU4YjQ4NC04NjQxLTQyYmEtYTExNC1lMWVhNTZiMjlhMmI'
var MAX_RUNNING_TIME = 5*35*6;
function launchProcessFolder() {
var scriptProperties = PropertiesService.getScriptProperties();
scriptProperties.setProperty('SOURCE_PARENT_FOLDER_KEY', SOURCE_PARENT_FOLDER_ID);
scriptProperties.setProperty('counter', 0);
scriptProperties.deleteProperty('CONTINUATION_TOKEN_KEY');
ScriptApp.newTrigger('continueProcess').timeBased().everyMinutes(10).create();
continueProcessFolder();
}
function continueProcessFolder() {
var startTime = (new Date()).getTime();
var scriptProperties = PropertiesService.getScriptProperties();
var srcParentFolderId = scriptProperties.getProperty('SOURCE_PARENT_FOLDER_KEY');
var continuationToken = scriptProperties.getProperty('CONTINUATION_TOKEN_KEY');
var iterator = continuationToken == null ? DriveApp.getFolderById(srcParentFolderId).getFolders() : DriveApp.continueFolderIterator(continuationToken);
var timeLimitIsNear = false;
var currTime;
var counter = Number(scriptProperties.getProperty('counter'));
while (iterator.hasNext() && !timeLimitIsNear) {
var folder = iterator.next();
counter++;
Logger.log(counter+' - '+folder.getName());
currTime = (new Date()).getTime();
timeLimitIsNear = (currTime - startTime >= MAX_RUNNING_TIME);
if (!iterator.hasNext()) {
scriptProperties.deleteProperty('CONTINUATION_TOKEN_KEY');
ScriptApp.deleteTrigger(ScriptApp.getProjectTriggers()[0]);
Logger.log('******************no more folders**************');
break;
}
}
if(timeLimitIsNear){
var contToken = iterator.getContinuationToken();
scriptProperties.setProperty('CONTINUATION_TOKEN_KEY', contToken);
scriptProperties.setProperty('counter', counter);
Logger.log('write to scriptProperties');
}
}
(另见最后评论)
这是一个测试,修改了脚本以获取文件夹中的文件。从我的不同测试看来,操作非常快,我需要设置一个非常短的超时限制,以便在到达列表末尾之前实现它。
我添加了几个Logger.log()
和一个counter
,以确切了解发生了什么,并确定是什么中断了while循环。
使用当前值,我可以看到它按预期工作,第一次(和第二次)中断发生时间限制,并且记录器确认写入了令牌。在第三次运行中,我可以看到所有文件都已被转储。
var SOURCE_PARENT_FOLDER_ID = '0B3qSFd3iikE3MS0yMzU4YjQ4NC04NjQxLTQyYmEtYTExNC1lMWVhNTZiMjlhMmI'
var MAX_RUNNING_TIME = 5*35*6;
function launchProcess() {
var scriptProperties = PropertiesService.getScriptProperties();
scriptProperties.setProperty('SOURCE_PARENT_FOLDER_KEY', SOURCE_PARENT_FOLDER_ID);
scriptProperties.setProperty('counter', 0);
scriptProperties.deleteProperty('CONTINUATION_TOKEN_KEY');
ScriptApp.newTrigger('continueProcess').timeBased().everyMinutes(10).create();
continueProcess();
}
function continueProcess() {
var startTime = (new Date()).getTime();
var scriptProperties = PropertiesService.getScriptProperties();
var srcParentFolderId = scriptProperties.getProperty('SOURCE_PARENT_FOLDER_KEY');
var continuationToken = scriptProperties.getProperty('CONTINUATION_TOKEN_KEY');
var iterator = continuationToken == null ? DriveApp.getFolderById(srcParentFolderId).getFiles() : DriveApp.continueFileIterator(continuationToken);
var timeLimitIsNear = false;
var currTime;
var counter = Number(scriptProperties.getProperty('counter'));
while (iterator.hasNext() && !timeLimitIsNear) {
var file = iterator.next();
counter++;
Logger.log(counter+' - '+file.getName());
currTime = (new Date()).getTime();
timeLimitIsNear = (currTime - startTime >= MAX_RUNNING_TIME);
if (!iterator.hasNext()) {
scriptProperties.deleteProperty('CONTINUATION_TOKEN_KEY');
ScriptApp.deleteTrigger(ScriptApp.getProjectTriggers()[0]);
Logger.log('******************no more files**************');
break;
}
}
if(timeLimitIsNear){
var contToken = iterator.getContinuationToken();
scriptProperties.setProperty('CONTINUATION_TOKEN_KEY', contToken);
scriptProperties.setProperty('counter', counter);
Logger.log('write to scriptProperties');
}
}
答案 1 :(得分:1)
截至2016年1月1日,这仍然是一个问题。错误报告使用Advanced Drive API which is documented here, under "Listing folders"列出了一个解决方案。
如果您不想使用高级服务,另一种解决方案是使用Folder Iterator创建一个File Ids数组。
在我看来,文件夹迭代器只有在使用DriveApp.continueFolderIterator()
创建时才会出现问题。使用此方法时,返回的文件夹迭代器中只包含100个文件夹。
根据执行记录,使用DriveApp.getFolders()
并且只获取文件夹ID,我能够在2.734秒内迭代694个文件夹。
function allFolderIds() {
var folders = DriveApp.getFolders(),
ids = [];
while (folders.hasNext()) {
var id = folders.next().getId();
ids.push(id);
}
Logger.log('Total folders: %s', ids.length);
return ids;
}
我使用返回的数组使用触发器在所有文件夹中工作。 Id数组太大而无法保存在缓存中,因此我创建了一个临时文件并使用缓存来保存临时文件ID。
答案 2 :(得分:0)
答案 3 :(得分:0)
似乎您只存储一个连续令牌。如果要递归遍历一组文件夹并允许脚本在任何时候暂停(例如,避免超时)并在以后恢复,则需要存储更多的连续令牌(例如,在对象数组中)
我已经outlined a template that you can use here使其正常运行。在30多个过程中,它可以处理数千个嵌套文件,完美运行。