使用google-api-client将大文件从客户端上传到GDrive,使用存储在内存中的烧瓶/python中的可断点



我正在尝试使用google-api-client将一个大文件上传到gdrive。 我正在使用可恢复上传。这里的问题是我不希望文件对象保存/写入我的文件系统。我希望它以块的形式读取它,因此使用可恢复上传将相同的块上传到 Gdrive。无论如何,我可以在可以通过谷歌 api python 客户端发送块的地方实现这一点。

这是我的示例代码,它可以工作,但它从客户端获取整个文件对象。

@app.route('/upload', methods = ["GET", "POST"])
def upload_buffer():
drive = cred()
if request.method == "POST":
mime_type = request.headers['Content-Type']
body = {
'name': "op.pdf",
'mimeType': mime_type,
}
chunk = BytesIO(request.stream.read()) # as you can see here the entire file stream is obtained 
#I want to read in chunks and simultaneously send that chunk to GDrive
#chunk = BytesIO(request.stream.read(1024))     
#if I send like the above only some part of the file is uploaded in Gdrive
media_body = MediaIoBaseUpload(chunk, chunksize = 1024, mimetype=mime_type,
resumable=True)
return drive.files().create(body=body,
media_body=media_body,
fields='id,name,mimeType,createdTime,modifiedTime').execute()
return render_template("upload_image.html")

<------------------------------------------------------------------->这就是我使用Google Rest API的方式

@app.route('/upload3', methods=["GET", "POST"])
def upload_buff():
if request.method == "POST":
Content_Length = request.headers['Content-Length']
access_token = '####'
headers = {"Authorization": "Bearer " + access_token, "Content-Type": "application/json", "Content-Length": Content_Length}
params = {
"name": "file_name.pdf",
"mimeType": "application/pdf"
}
r = requests.post("https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable", headers=headers, data=json.dumps(params))
location = r.headers['Location']
print("----------------------------------------------------")
print("GDrive Upload url : ", location)
print("----------------------------------------------------")
start = str(0)
while True:
chunk = request.stream.read(1024 * 1024)
chunk_size = len(chunk)
print("----------------------------------------------------")
print("Size of Received Chunk From Client:  ", chunk_size)
print("----------------------------------------------------")
if chunk_size == 0:
break
end = str(int(start)+chunk_size-1)
headers = {'Content-Range': 'bytes '+start+'-' + end + '/' +str(Content_Length), 'Content-Length': str(chunk_size)}
start = str(int(end)+1)
print("The headers set for the chunk upload : ", headers)
r = requests.put(location, headers=headers, data=chunk)
print("----------------------------------------------------")
print("Response content : ", r.content)
print("Response headers : ", r.headers)
print("Response status : ", r.status_code)
print("----------------------------------------------------")
return r.content
return render_template("upload_image.html")

阅读您的问题和代码,我假设您将流保存在名为chunk的变量中,并希望将其分成 1024 字节块以使用可恢复上传。如果我对问题的理解是正确的,您可以在字节对象中使用切片chunk类似于:

chunk = b"x04x09x09x01x01x01x00x03" # Example values
chunk[:3] # Equals to b"x04x09x09"
chunk[-3:] # Equals to b"x01x00x03"
chunk[4:2] # Equals to b"x01x01"

可以使用此方法将chunk切片为 1024 字节的部分。如果您需要更多帮助,请问我任何问题。


对于我对你的问题的错误理解,我深表歉意。我现在了解到您有一个字节对象被分成块,并希望使用可恢复上传将其上传到云端硬盘。如果我的实际假设是正确的,则可以使用我为该方案编写的代码。使用此代码,无需在硬盘驱动器上写入任何内容。

#!/usr/bin/python
# -*- coding: utf-8 -*-
import json
import locale
import requests
import sys
from io import BytesIO
accessToken = 
'{YOUR ACCESS TOKEN HERE}'
fileData = 
BytesIO(requests.get('https://upload.wikimedia.org/wikipedia/commons/c/cf/Alhambra_evening_panorama_Mirador_San_Nicolas_sRGB-1.jpg'
).content).getvalue()
fileSize = sys.getsizeof(fileData) - 129
# Step I - Chop data into chunks
wholeSize = fileSize
chunkSize = 4980736  # Almost 5 MB
chunkTally = 0
chunkData = []
while wholeSize > 0:
if (chunkTally + 1) * chunkSize > fileSize:
chunkData.append(fileData[chunkTally * chunkSize:fileSize])
else:
chunkData.append(fileData[chunkTally * chunkSize:(chunkTally
+ 1) * chunkSize])
wholeSize -= chunkSize
chunkTally += 1
# Step II - Initiate resumable upload
headers = {'Authorization': 'Bearer ' + accessToken,
'Content-Type': 'application/json'}
parameters = {'name': 'alhambra.jpg',
'description': 'Evening panorama of Alhambra from Mirador de San Nicolxc3xa1s, Granada, Spain.'}
r = 
requests.post('https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable'
, headers=headers, data=json.dumps(parameters))
location = r.headers['location']
# Step III - File upload
chunkTally = 0
for chunk in chunkData:
if (chunkTally + 1) * chunkSize - 1 > fileSize - 1:
finalByte = fileSize - 1
chunkLength = fileSize - chunkTally * chunkSize
else:
finalByte = (chunkTally + 1) * chunkSize - 1
chunkLength = chunkSize
headers = {'Content-Length': str(chunkLength),
'Content-Range': 'bytes ' + str(chunkTally * chunkSize) 
+ '-' + str(finalByte) + '/' + str(fileSize)}
r = requests.put(location, headers=headers, data=chunk)
print(r.text)  # Response
chunkTally += 1

例如,此脚本将从维基共享资源拍摄照片;您可以改用您的文件流。获取数据后,代码将根据变量使用的内存空间计算文件大小(因为它没有写入硬盘驱动器(。

下一步是将文件切成小于 5 MB 的块。我确保使用 1024*256 的倍数,如文档中详述的那样。数据将被迭代,直到它被分成5 MB 的块(最后一个除外(。

在该操作之后,代码将初始化使用 OAuth 2.0 进行身份验证的可恢复上传。在此步骤中,我为我的文件使用了一些示例元数据,但您可以阅读有关其他属性的 Files 属性。最后,脚本会将位置保存在变量中以供将来上传。

在最后一步中,块将被逐个迭代和上传。首先,根据规范构建标头。之后,我们已经准备好了标头、块和上传位置,因此我们可以继续在请求中正式化上传。上传每个区块后,将打印响应以记录错误,并在最后一个区块之后显示上传文件的元数据。这标志着整个操作的结束。最后,我想提一下,我在 Python3 中编写并测试了这个脚本。如果您有任何疑问,请随时向我询问一些澄清。

最新更新