首页 > 解决方案 > 如何将大文件分块并上传到 Google 存储桶

问题描述

我正在尝试从 nodejs 将较大的文件上传到谷歌存储桶。上传任何低于 200MB 大小标记的文件都可以正常工作。大于该值的任何内容都会返回错误

Cannot create a string longer than 0x1fffffe8 characters

通过我有一个那么大的文件,我发现该节点确实对 blob/文件的大小有限制。这是两个都抛出相同错误的代码片段

这个是上传流

let fileSize = file.size;
      fs.createReadStream(file)
        .pipe(
          upload({
            bucket: BUCKET,
            file: file,
          })
        )
        .on("progress", (progress) => {
          console.log("Progress event:");
          console.log("\t bytes: ", progress.bytesWritten);
          const pct = Math.round((progress.bytesWritten / fileSize) * 100);
          console.log(`\t ${pct}%`);
        })
        .on("finish", (test) => {
          console.log(test);
          console.log("Upload complete!");
          resolve();
        })
        .on("error", (err) => {
          console.error("There was a problem uploading the file");
          reject(err);
        });

当然只是一个常规的桶上传

await storage.bucket(BUCKET)
           .upload(file.path, {
             destination: file.name,
            })

我认为唯一的解决方案是对文件进行分块,分块上传,然后重新加入存储桶中的文件块。问题是我不知道该怎么做,而且我在 google 或 GitHub 上找不到该条款的任何文档

标签: javascriptnode.jsgoogle-cloud-platformfile-uploadgoogle-bucket

解决方案


为了解决这个问题,我检查了文件大小,看它是否大于 200MB。我将它分成 200MB 的块(大约)然后单独上传。然后使用 bucket.combine() 加入文件

一个非常重要的注意事项是添加超时。默认情况下,谷歌有 1 分钟的文件上传超时,我在下面的代码段中将其设置为 60 分钟。我必须承认这是一种非常老套的方法

if (uploadF.size > 209715200) {
    await splitFile
      .splitFileBySize(file.path, "2e8")
      .then(async (names) => {
        console.log(names);
        for (let i = 0; i < names.length; i++) {
          console.log("uploading " + names[i]);
          await storage
            .bucket(BUCKET)
            .upload(names[i], {
              destination: names[i],
              timeout: 3600000,
            })
            .catch((err) => {
              return { status: err };
            });
        }

        await bucket
          .combine(names, file.name)
          .catch((err) => {
            return {
              status: err,
            };
          });

        for (let i = 0; i < names.length; i++) {
          console.log("deleting " + names[i]);
          await storage
            .bucket(BUCKET)
            .file(names[i])
            .delete()
            .then(() => {
              console.log(`Deleted ${name[i]}`);
            })
            .catch((err) => {
              return { status: err };
            });
        }
        console.log("done");
        return { status: "ok" };
      })

推荐阅读