Как извлечь файлы из архива .tar с помощью скрипта Google Apps - PullRequest
0 голосов
/ 24 февраля 2019

Добрый день всем,

Я пытаюсь получить вложение tar.gz из Gmail, извлечь файл и сохранить его на Google Диске.Это ежедневный автоматически генерируемый отчет, который я получаю, сжатый из-за необработанного размера> 25 МБ.

Я получил это до сих пор:

  var sheet   = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Setup");

  var gmailLabels  = sheet.getRange("B2:B2").getValue();  //I have my Gmail Label stored here
  var driveFolder  = sheet.getRange("B5:B5").getValue();  //I have my GDrive folder name stored here

  // apply label filter, search only last 24hrs mail
  var filter = "has:attachment label:" + gmailLabels + " after:" + Utilities.formatDate(new Date(new Date().getTime()-1*(24*60*60*1000)), "GMT", "yyyy/MM/dd");

  var threads = GmailApp.search(filter, 0, 1); // check only 1 email at a time  

  var folder = DriveApp.getFoldersByName(driveFolder);

  if (folder.hasNext()) {
    folder = folder.next();
  } else {
    folder = DriveApp.createFolder(driveFolder);
  }


    var message = threads[0].getMessages()[0];

    var desc   = message.getSubject() + " #" + message.getId();
    var att    = message.getAttachments();

    for (var z=0; z<att.length; z++) {
      var attName = att[z].getName()
      var attExt = attName.search('csv')
      if (attExt > 0){ var fileType = "csv"; }
      else {
        var attExt = attName.search('tar.gz');
        if (attExt > 0){ var fileType = "gzip"; }
        else {
          threads[x].addLabel(skipLabel);  
          continue;
        }
      }

      // save the file to GDrive
      try {
        file = folder.createFile(att[z]);
        file.setDescription(desc);
      }
      catch (e) {
        Logger.log(e.toString());
      }

      // extract if gzip
      if (fileType == 'gzip' ){
        var ungzippedFile = Utilities.ungzip(file);
        try {
          gz_file = folder.createFile(ungzippedFile);
          gz_file.setDescription(desc);
        }
        catch (e) {
          Logger.log(e.toString());
        }
      }

    }

Все работает нормально, но на последнем шагеон распаковывает только файл .gz, сохраняя файл .tar на диске.Что я могу сделать с этим дальше?Файл .tar содержит файл .csv, который мне нужно извлечь и обработать впоследствии.

Я, вероятно, должен добавить, что я ограничен в использовании только ГАЗА.

Любая помощь горячо приветствуется.

1 Ответ

0 голосов
/ 27 февраля 2019

Как насчет этого ответа?К сожалению, на данном этапе пока нет способов извлечения файлов из файла tar в Google Apps Script.Но, к счастью, из вики tar мы можем получить структуру данных tar.Я реализовал этот метод с помощью Google Apps Script, используя данные этой структуры.

1.Разархивировать данные tar:

Перед запуском этого сценария установите для идентификатора файла tar файл run().Затем выполните run().

Пример сценария:

function tarUnarchiver(blob) {
  var mimeType = blob.getContentType();
  if (!mimeType || !~mimeType.indexOf("application/x-tar")) {
    throw new Error("Inputted blob is not mimeType of tar. mimeType of inputted blob is " + mimeType);
  }
  var baseChunkSize = 512;
  var byte = blob.getBytes();
  var res = [];
  do {
    var headers = [];
    do {
      var chunk = byte.splice(0, baseChunkSize);
      var headerStruct = {
        filePath: function(b) {
          var r = [];
          for (var i = b.length - 1; i >= 0; i--) {
            if (b[i] != 0) {
              r = b.slice(0, i + 1);
              break;
            }
          }
          return r;
        }(chunk.slice(0, 100)),
        fileSize: chunk.slice(124, 124 + 11),
        fileType: Utilities.newBlob(chunk.slice(156, 156 + 1)).getDataAsString(),
      };
      Object.keys(headerStruct).forEach(function(e) {
        var t = Utilities.newBlob(headerStruct[e]).getDataAsString();
        if (e == "fileSize") t = parseInt(t, 8);
        headerStruct[e] = t;
      });
      headers.push(headerStruct);
    } while (headerStruct.fileType == "5");
    var lastHeader = headers[headers.length - 1];
    var filePath = lastHeader.filePath.split("/");
    var blob = Utilities.newBlob(byte.splice(0, lastHeader.fileSize)).setName(filePath[filePath.length - 1]).setContentTypeFromExtension();
    byte.splice(0, Math.ceil(lastHeader.fileSize / baseChunkSize) * baseChunkSize - lastHeader.fileSize);
    res.push({fileInf: lastHeader, file: blob});
  } while (byte[0] != 0);
  return res;
}

// Following function is a sample script for using tarUnarchiver().
// Please modify this to your situation.
function run() {
  // When you want to extract the files from .tar.gz file, please use the following script.
  var id = "### file ID of .tar.gz file ###";
  var gz = DriveApp.getFileById(id).getBlob().setContentTypeFromExtension();
  var blob = Utilities.ungzip(gz).setContentTypeFromExtension();

  // When you want to extract the files from .tar file, please use the following script.
  var id = "### file ID of .tar file ###";
  var blob = DriveApp.getFileById(id).getBlob().setContentType("application/x-tar");

  // Extract files from a tar data.
  var res = tarUnarchiver(blob);

  // If you want to create the extracted files to Google Drive, please use the following script.
  res.forEach(function(e) {
    DriveApp.createFile(e.file);
  });

  // You can see the file information by below script.
  Logger.log(res);
}

2.Модификация вашего скрипта:

Если этот скрипт используется, например, для вашего скрипта, как насчет этого?tarUnarchiver() вышеприведенного скрипта используется.Но я не уверен, как вы хотите использовать этот скрипт.Поэтому, пожалуйста, подумайте об этом как о примере.

Пример сценария:

// extract if gzip
if (fileType == 'gzip' ){
  var ungzippedFile = Utilities.ungzip(file);
  try {

    var blob = ungzippedFile.setContentType("application/x-tar"); // Added
    tarUnarchiver(blob).forEach(function(e) {folder.createFile(e.file)}); // Added

  }
  catch (e) {
    Logger.log(e.toString());
  }
}
  • В этом модифицированном сценарии в мой сценарий добавлен блоб ungzippedFile (данные tar)и запустить tarUnarchiver().Затем каждый файл создается в папке.

Примечание:

  • При запуске этого скрипта, если возникает ошибка, связанная с mimeType, установитеmimeType «tar» для входного BLOB-объекта.
    • В качестве метода установки mimeType вы можете использовать следующее.
      • blob.setContentTypeFromExtension() Ref
      • blob.setContentType("application/x-tar") Ref
    • Возможно, он уже был полученmimeType в BLOB-объекте.В это время setContentTypeFromExtension() и setContentType() не требуются.
  • Если вы хотите получить путь к файлу каждого файла, проверьте ответ от tarUnarchiver().Вы можете видеть его как свойство fileInf из ответа.

Ограничения:

При использовании этого сценария существуют следующие ограничения.Эти ограничения обусловлены спецификацией Google.

  • Что касается размера файла, когда размер данных tar превышает 50 МБ (52 428 800 байт), возникает ошибка, связанная с ограничением размера.
  • Если размер извлеченного файла превышает 50 МБ, возникает ошибка.
  • Когда размер отдельного файла, извлеченного из файла, приближается к 50 МБ, возникает ошибка.
    • В моей среде я могу подтвердить, что можно извлечь размер 49 МБ.Но в случае только 50 МБ произошла ошибка.

Ссылка:

В моем окружении я мог подтвердить, что скрипт работает.Но если этот сценарий не работает, я прошу прощения.В то время, можете ли вы предоставить пример файла tar?Я хотел бы проверить это и изменить скрипт.

...