如何使用Apps脚本将云端硬盘中的现有文件上传到云端硬盘 [英] How to upload an existing file in Drive to Drive using Apps Script

查看:87
本文介绍了如何使用Apps脚本将云端硬盘中的现有文件上传到云端硬盘的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简介

首先让我介绍一下我要做什么的目标.

Let me first introduce the goal of what I am trying to do.

  • 我之前有一个文件分成两部分

  • I had a file split into two parts earlier

这两个文件的大小总和可能超过50 MB(作为长期目标).由于UrlFetchApp.fetch()对于请求的大小有限制,因此我想分别上传它们,其中每个文件小于50 MB,因此将它们合并.目前(尝试使用Drive API),我使用的是小文件.

Size of both of these files together may exceed 50 MB (as a long term goal). Since UrlFetchApp.fetch() has restriction regarding the size of the request, I want to upload them separately, where each file will be less than 50 MB and consequently merge them. For now (to try the Drive API), I am using small files.

第一个文件为 640000 bytes(256的倍数) 524288 bytes.我意识到我之前犯了一个错误,即我使用的文件大小是256的倍数,但它应该是256*1024

First file is of 640000 bytes (a multiple of 256) 524288 bytes. I realise I did a mistake earlier i.e I was using the size of the file as a multiple of 256 but it should be a multiple of 256*1024

第二个文件是 47626 bytes 163339 bytes.

我已经使用curl分割了文件并将其上传到驱动器(正常的网络上传).

I had split the files using curl and uploaded them to my drive (normal web upload).

我的意图是使用Google Apps Scriptpartial files逐个上传partial files到Google云端硬盘,以便将它们合并成一个文件.

My intention is to upload the partial files one by one using Resumable Upload to Google Drive using the Google Drive API from Google Apps Script so that they maybe merged into one file.

到目前为止我尝试过什么?

  • 昨天,我问过问题在这里.我试图使用Drive.Files.insert执行resumable upload,用户指出不可能使用下面引用的Drive.Files.insert.
  • Yesterday, I had asked a question here. I was trying to perform a resumable upload using Drive.Files.insert and a user pointed out it is not possible using Drive.Files.insert which is quoted below.

不幸的是,在当前阶段,无法使用Drive.Files.insert实现可恢复的上传.看来这是Google方面的当前规范

Unfortunately, in the current stage, the resumable upload cannot be achieved using Drive.Files.insert. It seems that this is the current specification at Google side

  • 我现在正在尝试使用Google Drive API.下面随附的代码.
    • What I am trying now is using Google Drive API. Enclosed below is the code.
    • function myFunction() {
          var token = ScriptApp.getOAuthToken();
      
          var f1_id = '1HkBDHV1oXXXXXXXXXXXXXXXXXXXXXXXX';
          var f2_id = '1twuaKTCFTXXXXXXXXXXXXXXXXXXXX';
          
          var putUrl = 'https://www.googleapis.com/drive/v3/files?uploadType=resumable';
        
          var fileData = {
              name : 'Merged-file-from-GAS',
              file : DriveApp.getFileById(f1_id).getBlob()
          }
          
          var options = {
            method : 'put',
            contentType:"application/json",
            headers : {
              Authorization: 'Bearer ' + token,
              'X-Upload-Content-Type' : 'application/octet-stream',
              'Content-Type' : 'application/json; charset=UTF-8'
            },
            muteHttpExceptions: true,
            payload : fileData
          };
        
          var response = UrlFetchApp.fetch(putUrl, options);
          Logger.log(response.getResponseCode());
          Logger.log(response.getAllHeaders()); 
      }
      
      

      • 我还尝试将方法更改为patch

        我在headers内添加了Content-Length : 640000,在这种情况下,我收到以下错误消息.

        I added Content-Length : 640000 inside headers and in that case I receive an error as provide below.

        异常:属性提供的值无效:Header:Content-Length

        Exception: Attribute provided with invalid value: Header:Content-Length

        • 我尝试使用空白<​​c20>和Drive.Files.insert(resource)创建文件.然后我尝试在具有变量的同时使用UrlFetchApp(patchUrl,options)更新它 var patchUrl = 'https://www.googleapis.com/upload/drive/v3/files/' + fileId + '?uploadType=resumable';
          • I tried to create a file using Drive.Files.insert(resource) using blank resource. Then I tried to update it using UrlFetchApp(patchUrl,options) while having the variable var patchUrl = 'https://www.googleapis.com/upload/drive/v3/files/' + fileId + '?uploadType=resumable';
          • 结果

            • 它不会创建任何文件.
            • 以下提供了附加代码(初始代码)结果的记录器日志:

            [20-05-12 21:05:37:726 IST] 404.0

            [20-05-12 21:05:37:726 IST] 404.0

            [20-05-12 21:05:37:736 IST] {X-Frame-Options = SAMEORIGIN,Content-Security-Policy = frame-ancestors'self',Transfer-Encoding = chunked,alt-svc = h3-27 =:443"; ma = 2592000,h3-25 =:443"; ma = 2592000,h3-Q050 =:443"; ma = 2592000,h3-Q049 =:443"; ma = 2592000,h3-Q048 =:443"; ma = 2592000,h3-Q046 =:443"; ma = 2592000,h3-Q043 =:443"; ma = 2592000,quic =:443"; ma = 2592000; v ="46,43",X-Content-Type-Options = nosniff,日期=星期二,2020年5月12日15:35:37 GMT,到期时间=星期一,1990年1月1日00:00:00 GMT,X-XSS -保护= 1;模式=块,内容编码= gzip,编译=无缓存,缓存控制=无缓存,无存储,最大使用期限= 0,必须重新验证,变量= [来源,X来源],服务器= GSE,Content-Type =文本/html; charset = UTF-8}

            [20-05-12 21:05:37:736 IST] {X-Frame-Options=SAMEORIGIN, Content-Security-Policy=frame-ancestors 'self', Transfer-Encoding=chunked, alt-svc=h3-27=":443"; ma=2592000,h3-25=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43", X-Content-Type-Options=nosniff, Date=Tue, 12 May 2020 15:35:37 GMT, Expires=Mon, 01 Jan 1990 00:00:00 GMT, X-XSS-Protection=1; mode=block, Content-Encoding=gzip, Pragma=no-cache, Cache-Control=no-cache, no-store, max-age=0, must-revalidate, Vary=[Origin, X-Origin], Server=GSE, Content-Type=text/html; charset=UTF-8}

            问题

            • 使用Apps脚本中的Drive API,同时将upload type保持为resumable的情况下,将驱动器中的文件initiating a upload正确地传输到驱动器的正确方法是什么?

            • What is the proper way of initiating a upload of a file in Drive to Drive using Drive API from Apps Script while keeping the upload type as resumable?

            后续请求应该是什么样的?这样可以将大于50 MB的文件随后上传到合并的文件中?

            What should subsequent requests be like? So that files above 50 MB can be subsequently uploaded to the merged file?

            编辑1

            使用更正后的文件块大小再次尝试过.同样的问题仍然存在.

            Tried it again using corrected file chunks sizes. Same problem persists.

            编辑2

            要理解答案中的代码,我仅使用了Tanaike代码的// 2中的代码来了解如何检索Location.

            To understand the code in the answer, I used the code in // 2 of Tanaike's code alone to understand how Location is retrieved.

            function understanding() {
              var token = ScriptApp.getOAuthToken();
              const filename = 'understanding.pdf';
              const mimeType = MimeType.PDF;
            
              const url = 'https://www.googleapis.com/drive/v3/files?uploadType=resumable';
              
              const res1 = UrlFetchApp.fetch(url, {
                method: "post",
                contentType: "application/json",
                payload: JSON.stringify({name: filename, mimeType: mimeType}),
                headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()
              }});
              const location = res1.getHeaders().Location;
              Logger.log(location);
            }
            

            这将创建一个大小为0 bytes的文件understanding.pdf.但是,Logger.log(location)记录null.

            This creates a file understanding.pdf of size 0 bytes. However, Logger.log(location) logs null.

            为什么会这样?

            错误在终点.设置为 https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable有效.它会检索位置.

            The mistake was in the end point. Setting it to https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable works. It retrieves the location.

            推荐答案

            从您的问题和答复中,我可以理解您的情况和目标,如下所示.

            From your question and replying, I could understand your situation and goal like below.

            • 在示例文件中,文件A"和文件B"分别为524,288字节和163,339字节.
            • 您测试过的脚本是您的问题中显示的脚本.
            • 您要使用断点续传来合并文件.
            • 合并文件的mimeType为PDF.

            为此,这个答案如何?

            • 很遗憾,您的脚本不完整,无法实现可恢复的上传.在Google Drive API上的可恢复上传的流程如下. 参考

            1. 请求检索用作上传数据端点的位置.
              • 在您的情况下,将创建新文件.因此,需要使用POST方法.
            1. Request for retrieving the location which is used as the endpoint for uploading data.
              • In your case, the new file is created. So it is required to use the POST method.
            • 在这种情况下,需要使用循环上传数据.然后使用PUT方法.
            • 在这里,每个文件的大小都是最重要的.如果除最后一个文件之外的文件大小不是262,144字节的倍数,则无法恢复运行断点续传.请注意这一点.

            对于上述流程,当示例脚本准备好后,它如下所示.

            For above flow, when the sample script is prepared, it becomes as follows.

            在这种情况下,将使用Drive API.因此,请在高级Google服务中启用Drive API.这样,可以在API控制台中自动启用Drive API.

            In this case, Drive API is used. So please enable Drive API at Advanced Google Services. By this, the Drive API is automatically enabled at API console.

            示例脚本的流程如下.

            1. 创建要在可恢复上传中使用的对象.
            2. 检索位置"以开始可恢复上传.
            3. 上载每个文件并合并它们.

            2.示例脚本.

            请复制并粘贴以下脚本.并且请设置文件ID.在这种情况下,请设置它们以便合并.请注意这一点.

            2. Sample script.

            Please copy and paste the following script. And please set the file IDs. In this case, please set them in order for merging. Please be careful this.

            function myFunction() {
              const fileIds = ["###", "###"];  // Please set the file IDs of the file "A" and "B" in order.
              const filename = "sample.pdf";
              const mimeType = MimeType.PDF;
            
              // 1. Create an object for using at the resumable upload.
              const unitSize = 262144;
              const fileObj = fileIds.reduce((o, id, i, a) => {
                const file = DriveApp.getFileById(id);
                const size = file.getSize();
                if (i != a.length - 1 && (size % unitSize != 0 || size > 52428800)) {
                  throw new Error("Size of each file is required to be the multiples of 262,144 bytes and less than 52,428,800 bytes.");
                }
                o.files.push({data: file.getBlob().getBytes(), range: `bytes ${o.size}-${o.size + size - 1}\/`, size: size.toString()});
                o.size += size;
                return o;
              }, {size: 0, files: []});
            
              // 2. Retrieve "location" for starting the resumable upload.
              const url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable";
              const res1 = UrlFetchApp.fetch(url, {
                method: "post",
                contentType: "application/json",
                payload: JSON.stringify({name: filename, mimeType: mimeType}),
                headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()
              }});
              const location = res1.getHeaders().Location;
            
              // 3. Upload each file and merge them.
              fileObj.files.forEach((e, i) => {
                const params = {
                  method: "put",
                  headers: {"Content-Range": e.range + fileObj.size},
                  payload: e.data,
                  muteHttpExceptions: true,
                };
                const res = UrlFetchApp.fetch(location, params);
                const status = res.getResponseCode();
                if (status != 308 && status != 200) {
                  throw new Error(res.getContentText());
                }
                if (status == 200) {
                  console.log(res.getContentText())
                }
              });
            
              // DriveApp.createFile()  // This comment line is used for automatically detecting the scope of "https://www.googleapis.com/auth/drive" by the script editor. So please don't remove this line.
            }
            

            结果:

            可恢复上传完成后,可以在日志中看到以下结果.您可以在根文件夹中看到合并的文件.

            Result:

            When the resumable upload is finished, the following result can be seen at the log. And you can see the merged file at the root folder.

            {
             "kind": "drive#file",
             "id": "###",
             "name": "sample.pdf",
             "mimeType": "application/pdf"
            }
            

            注意:

            • 这是一个简单的示例脚本.因此,请根据您的实际情况对此进行修改.
            • 我在上面的脚本中测试了文件A"和文件B"分别为524,288字节和163,339字节的示例情况.因此,当使用此脚本合并几个大小约为50 MB的文件时,会发生错误.
            • 如果在使用大文件时发生内存错误,则在当前阶段,这似乎是Google方面的规范.所以请注意这一点.
            • Note:

              • This is a simple sample script. So please modify this for your actual situation.
              • I tested above script for your sample situation that "file A" and "file B" are 524,288 bytes and 163,339 bytes. So when several files with about 50 MB in size are merged using this script, an error occurs.
              • If the memory error occurs when the large files are used, in the current stage, it seems that this is the specification of Google side. So please be careful this.
              • 这篇关于如何使用Apps脚本将云端硬盘中的现有文件上传到云端硬盘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆