Recursion 避免在将Google工作表递归转换为Excel时超过执行时间

Recursion 避免在将Google工作表递归转换为Excel时超过执行时间,recursion,google-apps-script,export-to-excel,google-apps,execution-time,Recursion,Google Apps Script,Export To Excel,Google Apps,Execution Time,我正在编写一个脚本,以浏览我的Google Drive中的一系列文件夹,复制文件夹结构,并将文件夹中包含的文件转换为Excel或Word 有三种可能的选择:谷歌表格文件应转换为Excel;谷歌文档文件到Word;其他文件应按原样复制 我使用递归函数来探索文件结构 脚本似乎可以工作,但我超出了允许的执行时间。分析执行记录,这似乎是因为将每个Google文件转换为MS Office文件需要约2秒的时间 有谁能建议: 转换文件的更快方法 一种跟踪递归进程运行到哪里的方法,以便我可以暂停并恢复该进程?

我正在编写一个脚本,以浏览我的Google Drive中的一系列文件夹,复制文件夹结构,并将文件夹中包含的文件转换为Excel或Word

有三种可能的选择:谷歌表格文件应转换为Excel;谷歌文档文件到Word;其他文件应按原样复制

我使用递归函数来探索文件结构

脚本似乎可以工作,但我超出了允许的执行时间。分析执行记录,这似乎是因为将每个Google文件转换为MS Office文件需要约2秒的时间

有谁能建议:

  • 转换文件的更快方法
  • 一种跟踪递归进程运行到哪里的方法,以便我可以暂停并恢复该进程?(我也希望能得到一些关于如何暂停和恢复流程的建议;-)
道歉如果这已经涵盖,我确实花了一些时间寻找答案,我可以看到类似的问题,但没有一个我能理解的解决方案

代码如下

function folderRecurse(folderToSearch, folderToSave){
  while (folderToSearch){ // the function has been passed a folder to search inside
    var searchFolderId = folderToSearch.getId(); // get the Id of the folder passed
    var currentFolder = DriveApp.getFolderById(searchFolderId); //open the search folder passed
    var newName = currentFolder.getName(); // get the name of the search folder passed
    var saveFolder = folderToSave.createFolder(newName);// make a copy of the search folder in the backup folder
    var subfolders = currentFolder.getFolders(); //get any subfolders of the folder passed
      while (subfolders.hasNext()){ // if there are subfolders, start again by passing the function the folder to search and the folder to save to
      var subfolder = subfolders.next();
      folderRecurse(subfolder, saveFolder);
    }
    // when there are no more folders left, deal with the files inside the folder
    var folderFiles = folderToSearch.getFiles();
    while (folderFiles.hasNext()){
      // get the file
      var thisFile = folderFiles.next();
      // get the file's name
      var thisFileName = thisFile.getName();
      //test the file type
      var fileType = thisFile.getMimeType();
      Logger.log(fileType);
      if (fileType == "application/vnd.google-apps.document"){ // this is a google doc-- save it as a word document
        //google docs to word method
      }
      else if (fileType == "application/vnd.google-apps.spreadsheet"){ // this is a spreadsheet -- save it as an excel file
        convertToXlsxAndSave(thisFile,saveFolder)
        Logger.log(thisFile.getName());
      }
      else { // save it as whatever kind of file it is
       thisFile.makeCopy(thisFile.getName(),saveFolder);
      }
    }
    return 0;
  }
  return 0;
}

function convertToXlsxAndSave(thisFile, saveFolder){

  //open the file as an excel sheet
  var url = "https://docs.google.com/feeds/download/spreadsheets/Export?key=" + thisFile.getId() + "&exportFormat=xlsx";

  // set parameters
  var params = {
      method      : "get",
      headers     : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
      muteHttpExceptions: true
    };

  // get the binary
  var blob = UrlFetchApp.fetch(url, params).getBlob();

  // name the binary with the fileName
  blob.setName(thisFile.getName() + ".xlsx");

  // save the binary into the proper folder
  saveFolder.createFile(blob);
}

function convertToDocxAndSave(thisFile, saveFolder){

  //open the file as a word doc sheet
  var url = "https://docs.google.com/feeds/download/documents/export/Export?id=" + thisFile.getId() + "&exportFormat=docx";

  // set parameters
  var params = {
      method      : "get",
      headers     : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
      muteHttpExceptions: true
    };

  // get the binary
  var blob = UrlFetchApp.fetch(url, params).getBlob();

  // name the binary with the fileName
  blob.setName(thisFile.getName() + ".docx");

  // save the binary into the proper folder
  saveFolder.createFile(blob);
}


function createMsOfficeVersions() {
  // this function works through the files in the folders enumerated below, and creates MS Office versions. Eg Google Sheets convert to Excel files, Google Docs to Word files. The files are stored in a folder for downloading to AC.

  // create a date-stamped folder within the backups folder

  var formattedDate = Utilities.formatDate(new Date(), "GMT+12", "dd MMMM yyyy");

  var backupLabel = "HAMP Survey MS Office backup versions " + formattedDate;

  // get the folder Ms Office versions
  var backupDir = DriveApp.getFolderById('XXXXXXX');

  // make a new date-stamped folder to save the files into
  var thisBackup = backupDir.createFolder(backupLabel);

  // get the Survey 2015-2016 folder and subfolders
  var hampSurveyFolder = DriveApp.getFolderById('XXXXXXXXX');

  // loop through all the folders. For each, create a new folder inside the backup folder, grab all the files, test if they are docs or spreadsheets, copy to the new folder. if they are neither, copy as is.
  folderRecurse(hampSurveyFolder,thisBackup);

}

如果Google Drive文件夹中有大量文件,则脚本可能会超时。您应该改为使用基于时间的触发器,该触发器每10分钟运行一次并转换文件,而文件迭代器应存储为属性,以便从先前停止的位置继续

function myFunction() {

  var props = PropertiesService.getScriptProperties();
  var token = props.getProperty('TOKEN');
  var files = continuationToken ? DriveApp.continueFileIterator(token) : DriveApp.getFiles();
  var start = Date.now();

  while (files.hasNext() && (Date.now() - start < 5*60*1000)) {
    var file = files.next();    
    // convert files    
  }

  if (files.hasNext()) {
    props.setProperty("TOKEN", files.getContinuationToken());
  } else {
    props.deleteProperty("TOKEN");
  }
}
函数myFunction(){
var props=PropertiesService.getScriptProperties();
var token=props.getProperty('token');
var files=continuationToken?DriveApp.continueFileInterator(令牌):DriveApp.getFiles();
var start=Date.now();
while(files.hasNext()&&(Date.now()-start<5*60*1000)){
var file=files.next();
//转换文件
}
if(files.hasNext()){
setProperty(“TOKEN”,files.getContinuationToken());
}否则{
props.deleteProperty(“代币”);
}
}

Amit。。。存储为属性的文件id正常。但是,除非你存储了你正在使用的子文件夹,否则如何返回到子循环递归迭代步骤呢?我认为还有一个文件夹迭代器。Sujay,好的观点。但是你的评论帮助我认识到递归循环通过子文件夹的路径总是相同的,所以也许我可以存储子文件夹并在那里继续。目前我的最佳计划是运行递归构造一个文件列表(所有文件夹中的ID列表),然后向转换中添加if语句,以检查当前文件是否已转换。非常慢,但是…@HamishTocher会保持状态数组帮助吗?制作一个数组(或哈希映射)以保留“文件id”-“状态”对。处理文件id后,将其标记为true。这样,在重新加载时,可以不断跳过文件和完整目录,直到遇到数组(或映射)中不存在的文件id,然后从该点开始。该地图将允许您轻松地查找给定的文件ID。@ HAMSHITECHER路径将变化,如果在2次执行的中间,对驱动器结构进行任何更改。