Google App Script "Exception: FILENAME.csv exceeds the maxmium file size" 的变通解决方案?

Workaround solutions to Google App Script "Exception: FILENAME.csv exceeds the maxmium file size"?

我正在构建一个 Google App Maker 应用程序,它将用户上传的 Excel CSV 电子表格文件作为输入。我想过多种可能的解决方案来从这个文件中读取数据,但我每次都遇到这个错误:"Exception: FILENAME.csv exceeds the maximum file size"。我尝试通过 parseCSV() 将数据提取到 Google Cloud SQL,通过 .getBlob().getDataAsString() 作为一个字符串读入并用“\n”拆分,然后写入所有数据到 Google 文档并尝试从那里读取它。但是,所有这些方法都导致了相同的错误。

是否有解决此最大文件大小问题的解决方案?

我想过将文件拆分成更小的 CSV 文件,但我不确定该怎么做。

您想将大型 CSV 文件转换为拆分电子表格。如果我的理解是正确的,这个解决方法怎么样?

这种情况的问题和解决方法:

  1. 这么大的CSV文件转换为电子表格时,由于单元格总数和文件大小,无法直接转换为电子表格。而且当尝试拆分大文件时,它也无法拆分,因为可以在 GAS 上使用的 blob 小于 50 MB(52,428,800 字节)。

    • 为了拆分这么大的文件,它在驱动器 API 中使用了 "Partial download" of files.get。
  2. 在我的环境中,当一个大小为 100 MB 的 CSV 文件用于此示例脚本时,当文件被拆分为 10 MB 时,大约需要 65 秒才能将一个块转换为电子表格。在这种情况下,当CSV文件完全转换时,将被认为超过执行GAS的限制时间(6分钟)。

    • 为了避免这种情况,需要实现从大型 CSV 文件到多个电子表格的可恢复转换。

准备:

为了使用此示例脚本,请在高级 Google 服务和 API 控制台启用驱动器 API。

在高级 Google 服务中启用驱动器 API v2

  • 在脚本编辑器上
    • 资源 -> 高级 Google 服务
    • 打开驱动器 API v2

Enable Drive API at API console

  • 在脚本编辑器上
    • 资源 -> 云平台项目
    • 查看API控制台
    • 在开始时,单击启用 APIs 并获取密钥等凭据。
    • 在左侧,单击“库”。
    • 在搜索 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);
}

用法:

使用时请根据自己的情况修改main()中的obj,运行main()。示例案例如下

假设如下。

  • 您想将大小为 100 MB 的 CSV 文件转换为 10 个电子表格。
  • 一个块的大小是 10 MB。
  • CSV 文件每 3 处理一次。

本例中,每个obj如下。请在每个 运行.

输入每个 obj
  1. var obj = {fileId: "#####", chunk: 10485760, files: 3, start: 0, fileName: "sample", number: 1}
    • {"nextStart": ### nextStart2 ###, "nextNumber": 4}createSplitSpreadsheet() 返回。
  2. var obj = {fileId: "#####", chunk: 10485760, files: 3, start: ### nextStart2 ###, fileName: "sample", number: 4}
    • {"nextStart": ### nextStart3 ###, "nextNumber": 7}createSplitSpreadsheet() 返回。
  3. var obj = {fileId: "#####", chunk: 10485760, files: 3, start: ### nextStart3 ###, fileName: "sample", number: 7}
    • {"nextStart": ### nextStart4 ###, "nextNumber": 10}createSplitSpreadsheet() 返回。
  4. var obj = {fileId: "#####", chunk: 10485760, files: 3, start: ### nextStart4 ###, fileName: "sample", number: 10}
    • nullcreateSplitSpreadsheet() 返回。

通过此流程,从大小为 100 MB 的 CSV 文件创建了 10 个电子表格。

如果null用于obj中的files,则自动计算files。但在这种情况下,执行GAS的限制时间可能已经结束。请注意这一点。

参考资料:

如果这不是你想要的,我很抱歉。