当前位置: 首页 > 知识库问答 >
问题:

如何使用应用程序脚本将驱动器中的现有文件上载到驱动器

齐奕
2023-03-14

介绍

首先让我介绍一下我要做的事情的目标。

>

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

    这两个文件的大小加在一起可能超过50 MB(作为一个长期目标)。由于UrlFetchApp.fetch()对请求的大小有限制,我想单独上传它们,其中每个文件将小于50 MB,并因此合并它们。现在(尝试驱动器API),我使用小文件。

    第一个文件是 640000字节(是 256524288字节。我意识到我之前犯了一个错误,即我使用的文件大小是256的倍数,但它应该是256*1024的倍数

    第二个文件是

    我使用curl分割文件,并将它们上传到我的驱动器(正常的网络上传)。

    我的意图是使用谷歌应用脚本中的谷歌驱动API部分文件一个接一个地上传到谷歌驱动,以便将它们合并到一个文件中。

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

    • 昨天,我在这里问了一个问题。我试图使用驱动器执行可恢复上传。文件夹。插入,用户指出无法使用驱动器。文件夹。插入下面引用的

    不幸的是,在当前阶段,无法使用驱动器实现可恢复上传。文件夹。插入这似乎是谷歌方面当前的规范

    • 我现在尝试的是使用Google Drive API。下面是代码
    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

    我在标题中添加了内容长度:640000,在这种情况下,我收到一个错误,如下所示。

    异常:提供无效值的属性:标头:内容长度

    • 我试图创建一个文件使用驱动器。Files.insert(资源)使用空白资源。然后我尝试使用UrlFetchApp(patchUrl,选项)更新它,同时使用变量var patchUrl='https://www.googleapis.com/upload/drive/v3/files/'fileId'?##恢复##############################################################################################################################

    后果

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

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

    [20-05-12 21:05:37:736 IST]{X-Frame-Options=SAMEORIGIN,内容安全策略=帧祖先的自我,传输编码=分块,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=2592000,h3-Q043=:443=:443; ma=2592000;v=“46,43”,X-Content-Type-Options=nosniff,Date=Tue,2020年5月12日15:35:37 GMT,Expires=Mon,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,必须重新验证,Vary=[Origin,X-Origin],Server=GSE,Content Type=text/html;字符集=UTF-8}

    问题

    >

  • 使用应用程序脚本中的驱动API,将驱动器中的文件上传到驱动器,同时将上传类型保持为可恢复的,正确的方法是什么?

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

    编辑1

    再次尝试使用修正的文件块大小。同样的问题依然存在。

    编辑2

    为了理解答案中的代码,我仅使用了Tanaike代码的/2中的代码来理解如何检索位置

    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);
    }
    

    这将创建一个文件理解。pdf大小0字节。然而,Logger。日志(位置)logsnull

    为什么会这样?

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


  • 共有2个答案

    董建德
    2023-03-14

    塔奈克的答案非常完美。它很优雅,甚至帮助我了解了数组。减少功能。在我问这个问题之前,我对JavaScript知之甚少,对使用Google Drive API几乎一无所知。

    我的意图是使用谷歌应用脚本作为语言,逐步学习可恢复上传的整个过程。以塔奈克的代码为参考,我写了一个脚本,它不是高效的、可管理的、优雅的,而是(至少)让我一步一步地了解可恢复上传的工作原理。我没有使用循环,没有对象,甚至没有数组。

    步骤1(声明必要的变量)

      var fileId1 = "XXXXXXXXXXX"; //id of the first file
      var fileId2 = "YYYYYYYYYYY"; //id of the second file
      var filename = "merged.pdf"; //name of the final merged file
      var mimeType = MimeType.PDF; //Mime type of the merged file
    

    步骤2(启动可恢复上传)

    //declare the end point
    const url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable";
    
    //Send the request
    //Method to be used is Post during initiation
    //No file is to be sent during initiation
    //The file name and the mime type are sent
    const res1 = UrlFetchApp.fetch(url, {
        method: "post",
        contentType: "application/json",
        payload: JSON.stringify({name: filename, mimeType: mimeType}),
        headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()
      }});
    

    步骤3(保存可恢复会话URI)

    const location = res1.getHeaders().Location;
    

    步骤4(a)(上传文件1)

    注意:步骤4(a)和(b)可以使用循环执行。在我的例子中,我使用了两次,没有循环

      var file = DriveApp.getFileById(fileId1); //get the first file
      var data = file.getBlob().getBytes(); //get its contents in bytes array
    
    //Method used is PUT not POST
    //Content-Range will contain the range from starting byte to ending byte, then a slash
    //and then file size
    //bytes array of file's blob is put in data
      var params = {
        method : "put",
        headers : {
          'Content-Range' : `bytes 0-524287/687627`
        },
        payload : data,
        muteHttpExceptions: true
      }; 
    
    //Request using Resumable session URI, and above params as parameter
    
      var result = UrlFetchApp.fetch(location,params);
    

    步骤4(b)(上传第二个文件)

    //Almost same as Step 4 (a)
    //The thing that changes is Content Range
    file = DriveApp.getFileById(fileId2);
      data = file.getBlob().getBytes();
    
      params = {
        method : "put",
        headers : {
          'Content-Range' : `bytes 524288-687626/687627`
        },
        payload : data,
        muteHttpExceptions : true
      };
    
      result = UrlFetchApp.fetch(location, params);
    

    现在,与其执行步骤4n次数,不如使用循环。

    此外,此代码不会检查过程中可能发生的错误。

    希望这段代码能帮助别人,尽管它更像是一个自学实验。:)

    董意蕴
    2023-03-14

    从你的问题和回答,我可以理解你的情况和目标如下。

    • 在示例文件中,“文件A”和“文件B”分别为524288字节和163339字节

    对于这个,这个答案怎么样?

    >

  • 不幸的是,您的脚本不完整,无法实现可恢复上传。Google Drive API上的可恢复上传流程如下所示。裁判

    • 请求检索用作上载数据endpoint的位置。
      • 在您的情况下,将创建新文件。因此需要使用POST方法
      • 在这种情况下,需要使用循环上传数据。并采用了PUT方法

      对于上面的流程,当准备好示例脚本时,它变成如下所示。

      在这种情况下,将使用Drive API。因此,请在高级谷歌服务中启用驱动器应用编程接口。这样,在API控制台就会自动启用Drive API。

      示例脚本的流程如下所示。

      1. 创建一个用于可恢复上传的对象
      2. 检索用于启动可恢复上传的“位置”
      3. 上传每个文件并合并它们

      请复制并粘贴以下脚本。并请设置文件ID。在这种情况下,请按合并顺序设置它们。请小心这个。

      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.
      }
      

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

      {
       "kind": "drive#file",
       "id": "###",
       "name": "sample.pdf",
       "mimeType": "application/pdf"
      }
      
      • 这是一个简单的示例脚本。所以请根据你的实际情况修改这个。
      • 我测试了上面的脚本,用于你的示例情况,文件A和文件B分别是524,288字节和163,339字节。因此,当使用此脚本合并几个大小约为50 MB的文件时,会发生错误。
      • 如果使用大文件时出现内存错误,在当前阶段,似乎这是谷歌方面的规范。所以请小心。
      • 执行可恢复的上传

  •  类似资料:
    • 我是否需要登录到google cloud来访问身份验证令牌或凭据的API

    • 问题内容: 使用此代码,我上传文件,但该文件作为文档上传。表示我上传该文件的任何类型都将作为文档上传到Google驱动器 问题答案: 据我所知(距离我查看已经有几个月了 ) ,谷歌驱动器API 还不支持(至今?) 。解决方法是考虑安装本机google驱动器共享,然后将要上传的文件写入本地映射的共享文件夹中。然后它的谷歌驱动器问题来处理上传。

    • 我正在用Google Apps脚本编写一个JavaScript工具来检查文档的一些属性,比如“所有链接是否有效”、“权限设置是否正确”等等。我正在使用中记录的APIhttps://developers.google.com/apps-script/reference/drive/drive-app通过ID查找文件,检查它们的权限,在GoogleDrive中找到它们,等等,但是我发现“共享驱动器”与

    • 我尝试使用REST API将一个简单的文本作为文件上传到oneDrive。 我创造了一个象征:https://login.microsoftonline.com/ < li >授予类型客户端凭据 < li >客户端id我的客户端id < li>client_secret我的客户端机密 < Li > https://graph.microsoft.com/.default范围 Content-Typ

    • > 我想从上到下滚动android移动应用程序页面。 我尝试了以下定义的滚动编码,并使用文本单击特定的网络元素。它工作正常。 //滚动到页面底部

    • 我使用以下JCIFS代码将文件从本地磁盘复制到共享驱动器 复制10 mb文件需要10分钟以上。而当我直接复制同一个文件时,大约需要1分钟。我尝试了3种方法来复制文件(请参阅代码的注释部分),但没有一种方法显示出任何显著的差异。 是否有任何方法可以提高JCIFS的性能?