如何使用Apps脚本将云端硬盘中的现有文件上传到云端硬盘 [英] How to upload an existing file in Drive to Drive using Apps Script
问题描述
简介
首先让我介绍一下我要做什么的目标.
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 Script
将partial 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
usingDrive.Files.insert
and a user pointed out it is not possible usingDrive.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
insideheaders
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 blankresource
. Then I tried to update it usingUrlFetchApp(patchUrl,options)
while having the variablevar patchUrl = 'https://www.googleapis.com/upload/drive/v3/files/' + fileId + '?uploadType=resumable';
- 它不会创建任何文件.
- 以下提供了附加代码(初始代码)结果的记录器日志:
-
使用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 theupload type
asresumable
?
结果
[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}
问题
后续请求应该是什么样的?这样可以将大于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 howLocation
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 size0 bytes
. However,Logger.log(location)
logsnull
.为什么会这样?
错误在终点.设置为
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上的可恢复上传的流程如下. 参考
- 请求检索用作上传数据端点的位置.
- 在您的情况下,将创建新文件.因此,需要使用POST方法.
- 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字节的倍数,则无法恢复运行断点续传.请注意这一点.
- 我尝试使用空白<c20>和
- 创建要在可恢复上传中使用的对象.
- 检索位置"以开始可恢复上传.
- 上载每个文件并合并它们.
对于上述流程,当示例脚本准备好后,它如下所示.
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.
示例脚本的流程如下.
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方面的规范.所以请注意这一点.
- 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.
Note:
这篇关于如何使用Apps脚本将云端硬盘中的现有文件上传到云端硬盘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!