正确使用DriveApp.continueFileIterator(continuationToken)

时间:2014-03-12 23:01:08

标签: google-apps-script google-drive-api

我编写了一个脚本来迭代Google云端硬盘文件夹中的大量文件。由于我对这些文件进行的处理,它超过了最大执行时间。当然,我写入脚本使用DriveApp.continueFileIterator(continuationToken):令牌存储在Project Properties中,当脚本运行时,它会检查是否有令牌,如果有则从令牌创建FileIterator,如果不是重新开始。

我发现,即使脚本使用延续令牌重新启动,它仍然从迭代开始时开始,尝试再次处理相同的文件,这会浪费后续执行的时间。我是否错过了一些重要的东西,如命令或方法,让它从它停止的地方开始?我是否应该在while(contents.hasNext())循环中的各个阶段更新延续令牌?

以下是缩小示例代码,以便您了解:

function listFilesInFolder() {
  var id= '0fOlDeRiDg';
  var scriptProperties = PropertiesService.getScriptProperties();
  var continuationToken = scriptProperties.getProperty('IMPORT_ALL_FILES_CONTINUATION_TOKEN');
  var lastExecution = scriptProperties.getProperty('LAST_EXECUTION');
  if (continuationToken == null) {
    // first time execution, get all files from drive folder
    var folder = DriveApp.getFolderById(id);
    var contents = folder.getFiles();
    // get the token and store it in a project property
    var continuationToken = contents.getContinuationToken();
    scriptProperties.setProperty('IMPORT_ALL_FILES_CONTINUATION_TOKEN', continuationToken);
  } else {
    // we continue to import from where we left
    var contents = DriveApp.continueFileIterator(continuationToken);
  }
  var file;
  var fileID;
  var name;
  var dateCreated;

  while(contents.hasNext()) {
    file = contents.next();
    fileID = file.getId();
    name = file.getName();
    dateCreated = file.getDateCreated();
    if(dateCreated > lastExecution) {
      processFiles(fileID);
    }
  }
  // Finished processing files so delete continuation token
  scriptProperties.deleteProperty('IMPORT_ALL_FILES_CONTINUATION_TOKEN');
  var currentExecution = Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd HH:mm:ss");
  scriptProperties.setProperty('LAST_EXECUTION',currentExecution);
};

2 个答案:

答案 0 :(得分:15)

像乔纳森说的那样,你错误地比较了日期。但这不是你的剧本的主要问题,也不是你问的问题。

您遇到错误的主要概念是在执行循环之前无法保存延续令牌。获得令牌后,它会保存您当时所处的位置,如果您继续进行迭代,则表示未保存,您将在稍后重复这些步骤,就像您正在体验一样。

要在以后获取令牌,您不能让脚本因错误而终止。您必须在5分钟内测量可以处理的文件数量,然后在此之前手动停止脚本,这样您就有机会保存令牌。

这是正确的做法:

function listFilesInFolder() {
  var MAX_FILES = 20; //use a safe value, don't be greedy
  var id = 'folder-id';
  var scriptProperties = PropertiesService.getScriptProperties();
  var lastExecution = scriptProperties.getProperty('LAST_EXECUTION');
  if( lastExecution === null )
    lastExecution = '';

  var continuationToken = scriptProperties.getProperty('IMPORT_ALL_FILES_CONTINUATION_TOKEN');
  var iterator = continuationToken == null ?
    DriveApp.getFolderById(id).getFiles() : DriveApp.continueFileIterator(continuationToken);


  try { 
    for( var i = 0; i < MAX_FILES && iterator.hasNext(); ++i ) {
      var file = iterator.next();
      var dateCreated = formatDate(file.getDateCreated());
      if(dateCreated > lastExecution)
        processFile(file);
    }
  } catch(err) {
    Logger.log(err);
  }

  if( iterator.hasNext() ) {
    scriptProperties.setProperty('IMPORT_ALL_FILES_CONTINUATION_TOKEN', iterator.getContinuationToken());
  } else { // Finished processing files so delete continuation token
    scriptProperties.deleteProperty('IMPORT_ALL_FILES_CONTINUATION_TOKEN');
    scriptProperties.setProperty('LAST_EXECUTION', formatDate(new Date()));
  }
}

function formatDate(date) { return Utilities.formatDate(date, "GMT", "yyyy-MM-dd HH:mm:ss"); }

function processFile(file) {
  var id = file.getId();
  var name = file.getName();
  //your processing...
  Logger.log(name);
}

无论如何,有可能在您的运行之间创建一个文件,而您在继续迭代时却无法获得该文件。然后,通过在上次运行后保存执行时间,您也可能在下次运行时错过它。我不知道你的用例,如果最终重新处理某些文件或错过一些文件是可以接受的。如果你根本没有任何一种情况,那么我看到的唯一解决方案就是保存你已经处理过的所有文件的ID。您可能需要将它们存储在驱动器文件中,因为对于太多的ID,PropertiesService可能太小。

答案 1 :(得分:1)

您的日期比较不会以您拥有的方式运作。

var currentExecution = Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd HH:mm:ss");

将存储"2014-04-18 08:32:01",而文件日期file.getDateCreated()将返回Date对象,使用<>比较这些对象将始终返回false。

因此我建议您将时间存储为时间戳(因为您无法存储Date对象),然后将其与文件创建日期的时间戳进行比较。

// stored time stamp
var lastExecution = scriptProperties.getProperty('LAST_EXECUTION');

…

dateCreated = file.getDateCreated().getTime();

…

var currentExecution = new Date().getTime();
scriptProperties.setProperty('LAST_EXECUTION',currentExecution);

该比较将按预期工作。