简体   繁体   English

将Google表格递归转换为Excel时避免超过执行时间

[英]Avoiding exceeding execution time when recursively converting Google Sheets to Excel

I am working on a script to go through a series of folders in my Google Drive, make copies of the folder structure, and convert files contained in the folders to Excel or Word. 我正在编写一个脚本,以检查Google云端硬盘中的一系列文件夹,制作文件夹结构的副本,并将文件夹中包含的文件转换为Excel或Word。

There are three possible options: Google Sheets files should be converted to Excel; 共有三个选项:Google表格文件应转换为Excel; Google Docs files to Word; 将Google Docs文件转换为Word; and other files should be copied as-is. 其他文件应照原样复制。

I am using a recursive function to explore the file structure. 我正在使用递归函数来探索文件结构。

The script seems to work, but I am exceeding the allowable execution time. 该脚本似乎可以运行,但是我超出了允许的执行时间。 Analysing the Execution transcript, this would appear to be because of the ~2 seconds it takes to convert each Google file to an MS-Office file. 分析执行记录,这似乎是由于将每个Google文件转换为MS-Office文件大约需要2秒钟的时间。

Can anyone suggest either: 谁能建议:

  • a faster method of converting files? 更快的文件转换方法?
  • a method for keeping track of where the recursive process is up to, so that I can pause and resume the process? 一种跟踪递归过程的位置的方法,以便我可以暂停和继续该过程? (I'd also appreciate some advice on HOW to pause and resume the process ;-) (我也很感谢有关如何暂停和恢复该过程的一些建议;-)

Apologies if this has been covered, I did spend some time searching to find answers to this, and I can see similar questions but not a solution that I can understand. 抱歉,如果已解决此问题,我确实花了一些时间来寻找答案,但我可以看到类似的问题,但我无法理解的解决方案。

Code below. 下面的代码。

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);

}

If the Google Drive folder has a large number of files, the script is likely to timeout. 如果Google云端硬盘文件夹中包含大量文件,则脚本可能会超时。 You should instead use a time-based trigger that runs every 10 minutes and converts the files while the file iterator should be stored as a property to continue from where it left off earlier. 相反,您应该使用基于时间的触发器,该触发器每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");
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM