Обходные решения для исключения Google App Script: FILENAME.csv превышает максимальный размер файла?

Я создаю приложение Google App Maker, которое принимает загруженный пользователем файл электронной таблицы Excel CSV в качестве входных данных. Я думал о нескольких возможных решениях для чтения данных из этого файла, но каждый раз сталкивался с этой ошибкой: «Исключение: FILENAME.csv превышает максимальный размер файла». Я попытался извлечь данные через parseCSV() в Google Cloud SQL, прочитать как одну строку через .getBlob().getDataAsString() и разделить ее на "\n", записать все данные в Документы Google и попытаться прочитать это оттуда. Однако все эти методы привели к одной и той же ошибке.

Есть ли какое-либо обходное решение для решения этой проблемы с максимальным размером файла?

Я думал разбить файл на более мелкие CSV-файлы, но не знаю, как это сделать.


person Eric    schedule 25.06.2018    source источник
comment
Можете ли вы указать размер файла и количество строк в вашем CSV-файле?   -  person Tanaike    schedule 26.06.2018
comment
@Tanaike Мой файл имеет размер 56,5 МБ. CSV-файл Excel содержит 16 столбцов и 370 573 строки.   -  person Eric    schedule 26.06.2018


Ответы (1)


Вы хотите преобразовать большой CSV-файл в разделенную электронную таблицу. Если я правильно понимаю, как насчет этого обходного пути?

Проблемы и обходные пути для этой ситуации:

  1. Когда такой большой файл CSV преобразуется в электронную таблицу, он не может напрямую конвертироваться в электронную таблицу из-за общего количества ячеек и размера файла. А также, когда большой файл пытаются разделить, он не может этого сделать, потому что большой двоичный объект, который можно использовать в GAS, меньше 50 МБ (52 428 800 байт).

    • In order to split such large file, it uses "Partial download" of files.get in Drive API.
  2. В моей среде, когда для этого примера сценария используется CSV-файл размером 100 МБ, когда файл разбит на 10 МБ, для преобразования фрагмента в электронную таблицу требовалось около 65 секунд. В этом случае, когда файл CSV будет полностью преобразован, считается, что время ограничения (6 минут) для выполнения GAS истекло.

    • In order to avoid this, it is required to implement the resumable conversion from the large CSV-file to several spreadsheets.

Подготовить :

Чтобы использовать этот образец скрипта, включите Drive API в консоли Advanced Google Services и API.

Включите Drive API v2 в Advanced Google Services

  • On script editor
    • Resources -> Advanced Google Services
    • Включите Drive API v2

Включить Drive API в консоли API

  • On script editor
    • Resources -> Cloud Platform project
    • Посмотреть консоль API
    • В разделе «Начало работы» нажмите «Включить API» и получите учетные данные, такие как ключи.
    • С левой стороны нажмите «Библиотека».
    • В разделе «Поиск API и сервисов» введите «Диск». И нажмите Drive API.
    • Нажмите кнопку Включить.
    • Если API уже включен, не выключайте его.

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

function createSplitSpreadsheet(obj) {
  var accessToken = ScriptApp.getOAuthToken();
  var baseUrl = "https://www.googleapis.com/drive/v3/files/";

  // Retrieve file size.
  var url1 = baseUrl + obj.fileId + "?fields=size";
  var params1 = {
    method: "get",
    headers: {Authorization: "Bearer " + accessToken},
  };
  var fileSize = Number(JSON.parse(UrlFetchApp.fetch(url1, {headers: {Authorization: "Bearer " + accessToken}}).getContentText()).size);

  // Calculate number of output files.
  if (obj.files == null) {
    obj.number = 1;
    obj.start = 0;
  }
  var start = obj.start;
  var end = start + obj.chunk;
  var useFileSize = fileSize - start;
  f = Math.floor(useFileSize / obj.chunk);
  f = useFileSize % obj.chunk > 0 ? f + 1 : f;
  if (f < obj.files || obj.files == null) {
    obj.files = f;
  }

  // Split large file by chunk size (bytes).
  var url2 = baseUrl + obj.fileId + "?alt=media";
  var i;
  for (i = 0; i < obj.files; i++) {
    var params = {
      method: "get",
      headers: {
        Authorization: "Bearer " + accessToken,
        Range: "bytes=" + start + "-" + end,
      },
    };
    var res = UrlFetchApp.fetch(url2, params).getContentText();
    var e = res.lastIndexOf("\n");
    start += e + 1;
    end = start + obj.chunk;
    Drive.Files.insert(
      {mimeType: MimeType.GOOGLE_SHEETS, title: obj.fileName + (i + obj.number)},
      Utilities.newBlob(res.substr(0, e), MimeType.CSV)
    );
  }

  // Return next start value if there is a next chunk for the resume.
  if (start < fileSize) {
    return {nextStart: start, nextNumber: i + obj.number};
  } else {
    return null;
  }
}

// Please run this function.
function main() {
    var obj = {
        fileId: "#####", // File ID of the large CSV file.
        chunk: 10485760, // 10MB Please modify this for your situation.
        files: 3, // Please input the number of files you want to convert.
        start: 0,
        fileName: "sample",
        number: 1, // Counter of output files. Please input this as a next number.
    };
    var nextStart = createSplitSpreadsheet(obj);
    Logger.log(nextStart);
}

Применение :

Когда вы используете это, измените obj в main() для вашей ситуации и запустите main(). Примерный случай выглядит следующим образом.

Он предполагает следующее.

  • Вы хотите преобразовать файл CSV размером 100 МБ в 10 электронных таблиц.
  • Размер одного чанка составляет 10 МБ.
  • Файл CSV обрабатывается каждые 3.

В этом примере каждый obj выглядит следующим образом. Пожалуйста, вводите каждый obj при каждом запуске.

  1. var obj = {fileId: "#####", chunk: 10485760, files: 3, start: 0, fileName: "sample", number: 1}
    • {"nextStart": ### nextStart2 ###, "nextNumber": 4} is returned from createSplitSpreadsheet().
  2. var obj = {fileId: "#####", chunk: 10485760, files: 3, start: ### nextStart2 ###, fileName: "sample", number: 4}
    • {"nextStart": ### nextStart3 ###, "nextNumber": 7} is returned from createSplitSpreadsheet().
  3. var obj = {fileId: "#####", chunk: 10485760, files: 3, start: ### nextStart3 ###, fileName: "sample", number: 7}
    • {"nextStart": ### nextStart4 ###, "nextNumber": 10} is returned from createSplitSpreadsheet().
  4. var obj = {fileId: "#####", chunk: 10485760, files: 3, start: ### nextStart4 ###, fileName: "sample", number: 10}
    • null is returned from createSplitSpreadsheet().

По этому потоку создается 10 электронных таблиц из CSV-файла размером 100 МБ.

Если null используется вместо files в obj, files вычисляется автоматически. Но в этом случае может истечь срок давности исполнения ГАС. Пожалуйста, будьте осторожны с этим.

Использованная литература :

Если это не то, что вы хотите, извините.

person Tanaike    schedule 26.06.2018