R V*_*HAL 3 java multipartform-data google-drive-api
我需要帮助编写大文件(> 5MB)的分段和可恢复上传,到目前为止,我只能启动分段上传,但我不知道当用户暂停或网络故障时如何恢复它。
我所说的“恢复”是指我不知道如何
1) 获取已上传到驱动器的总字节数
2) 如何在 Content-Range 标头中使用该值
3)如何通过用户交互来暂停此上传[executeAsInputStream()也许?]
这就是我到目前为止所做的。即使我要强行停止应用程序并重新启动它,我也需要代码从停止上传的位置恢复
Drive service = GDrive.getService(); //Drive Specific Initialization Copied From QuickStart But with DriveScopes.FILES
File fileMetadata = new File();
fileMetadata.setName("Video.mp4"); //Video File
fileMetadata.setMimeType("application/vnd.google-apps.video");
java.io.File filePath = new java.io.File("E:\\large-file-60MB.mp4");//Large File Of 60 Mega Bytes
FileContent mediaContent = new FileContent("video/mp4",filePath);
Drive.Files.Create create=service.files().create(fileMetadata,mediaContent);
MediaHttpUploader uploader=create.getMediaHttpUploader();
uploader.setDirectUploadEnabled(false); //Use Resumable MultiPart Upload Protocol
uploader.setChunkSize(2*MediaHttpUploader.MINIMUM_CHUNK_SIZE); //Chunks Of Bytes To Upload With Each Request
// HttpHeaders headers=new HttpHeaders();
// headers.put("Content-Range",?); //This is not actual code which I used here but after reading the drive docs they talk about this header and I am not sure how or when to use it
// uploader.setInitiationHeaders(headers);
uploader.setProgressListener((uploading)->
{
switch (uploading.getUploadState())
{
case INITIATION_STARTED:System.out.println("Initiation has started!");
break;
case INITIATION_COMPLETE:System.out.println("Initiation is complete!");
break;
case MEDIA_IN_PROGRESS:
System.out.println("Progress="+uploading.getProgress());
System.out.println("Bytes="+uploading.getNumBytesUploaded());
break;
case MEDIA_COMPLETE:System.out.println("Upload is complete!");
}
});
create.execute();
Run Code Online (Sandbox Code Playgroud)
虽然在一个答案中回答多个问题通常不适合 Stack Overflow,但似乎这些问题都是紧密相连的,因此将概述可恢复上传,并在此过程中尝试解决您的三点:
- 如何获取已上传到云端硬盘的总字节数
- 如何使用 Content-Range 标头中的值
- 如何暂停可续传上传
来自 Google 关于Java API 客户端库文档上的直接和可恢复媒体上传的文档:
实施细节
主要感兴趣的类是MediaHttpUploader和MediaHttpProgressListener。
如果特定于服务的生成库中的方法包含Discovery 文档
mediaUpload中的参数,则会为这些方法创建一个采用 InputStreamContent 作为参数的便捷方法。例如
insertDrive API的方法支持mediaUpload,可以使用如下代码上传文件:
class CustomProgressListener implements MediaHttpUploaderProgressListener {
public void progressChanged(MediaHttpUploader uploader) throws IOException {
switch (uploader.getUploadState()) {
case INITIATION_STARTED:
System.out.println("Initiation has started!");
break;
case INITIATION_COMPLETE:
System.out.println("Initiation is complete!");
break;
case MEDIA_IN_PROGRESS:
System.out.println(uploader.getProgress());
break;
case MEDIA_COMPLETE:
System.out.println("Upload is complete!");
}
}
}
File mediaFile = new File("/tmp/driveFile.jpg");
InputStreamContent mediaContent =
new InputStreamContent("image/jpeg",
new BufferedInputStream(new FileInputStream(mediaFile)));
mediaContent.setLength(mediaFile.length());
Drive.Files.Insert request = drive.files().insert(fileMetadata, mediaContent);
request.getMediaHttpUploader().setProgressListener(new CustomProgressListener());
request.execute();
Run Code Online (Sandbox Code Playgroud)
然而,这些类抽象了创建可续传上传时返回的位置 URI 之类的内容,因此,如果您希望能够执行此操作,则需要遵循此处记录的可续传上传启动步骤。但这都是手动完成的,而不是直接使用 Google Drive API 客户端库。
要回答第一点,如何存储已上传的字节数取决于您。不要考虑“云端硬盘上已有多少内容”,而要考虑“我已经上传了多少内容?” 。
如果您愿意,您可以将其存储为本地变量,因为它将是您的块大小的倍数(2 * MediaHttpUploader.MINIMUM_CHUNK_SIZE在您的情况下)并且应该易于跟踪。
问题是,这实际上并不需要。您可以根据文档(强调我自己的文档)使用通配符来指示文件的当前位置未知:
如果上传请求在响应之前终止,或者收到 503 Service Unavailable 响应,则需要恢复中断的上传。
要请求上传状态,请创建一个
PUT针对可恢复会话 URI 的空请求。添加
Content-Range标头以指示文件中的当前位置未知。例如,如果文件总长度为 2,000,000 字节,则将Content-Range设为。*/2000000如果您不知道文件的完整大小,请将Content-Range设为*/*。
如果您确实想跟踪字节,可以在Content-Range标头中将其指定为
Content-Range: bytes_so_far/total_bytes
Run Code Online (Sandbox Code Playgroud)
要初始化可续传上传,您需要POST向/uploadDrive API 的端点发出请求。您不需要为此使用 Drive API 客户端库(实际上,如果您想获取可恢复会话 URI,则不能,因为客户端库没有提供此功能)。
假设您的凭证定义来自:
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(...);
Run Code Online (Sandbox Code Playgroud)
然后发出POST包含文件元数据的请求:
URL requestUrl = new URL("https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable");
String requestBody = "{\"name\": \"fileName\"}";
HttpURLConnection request = (HttpURLConnection) requestUrl.openConnection();
request.setRequestMethod("POST");
request.setDoInput(true);
request.setDoOutput(true);
request.setRequestProperty("Authorization", "Bearer " + credential.getToken());
request.setRequestProperty("X-Upload-Content-Type", "file/mimetype");
request.setRequestProperty("X-Upload-Content-Length", number_of_bytes_of_your_file);
request.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
request.setRequestProperty("Content-Length", String.format(Locale.ENGLISH, "%d", requestBody.getBytes().length));
OutputStream outputStream = request.getOutputStream();
outputStream.write(requestBody.getBytes());
outputStream.close();
request.connect();
Run Code Online (Sandbox Code Playgroud)
会话 URI(在需要时调用以恢复的位置)在 API 响应的标头中返回。连接后,您可以从响应中获取此 URI:
if (request.getResponseCode() == HttpURLConnection.HTTP_OK) {
URL sessionUri = new URL(request.getHeaderField("location"));
}
Run Code Online (Sandbox Code Playgroud)
现在您有了会话 URI - 有了它,您可以根据需要将文件块上传到云端硬盘。您现在需要使用此 URI 作为连续上传的上传点。
但请记住:可恢复会话 URI 将在一周后过期。
实际上这取决于您希望如何实现。例如,您可以打破一个循环,或者PAUSE THIS UPLOAD在 GUI 中使用一个巨大的按钮来切换是否继续上传的下一部分。
要记住的是,上传文件内容时,发出的请求必须使用HTTP PUT而不是POST. 接上一节:
Content-Range: bytes_so_far/total_bytes
Run Code Online (Sandbox Code Playgroud)
然后您可以重复调用上传块代码;在循环中,作为函数;你喜欢怎样。由于它是一个独特的代码块,您可以根据需要调用它,从而实现某种暂停上传的方法(通过中断、睡眠、等待等)。
请记住:您需要保存会话 URI 才能恢复。
直接使用 Drive V3 API 来进行断点续传似乎还不太可能。Java客户端库文档在讨论何时使用Drive: create与非特定于服务的库时提到了这一点:
...Drive API 的 insert 方法支持
mediaUpload,您可以使用以下代码上传文件:
代码块
Run Code Online (Sandbox Code Playgroud)You can also use the resumable media upload feature without the service-specific generated libraries.
不过,您可以让 Google 知道这是一项对 Drive API 直接重要的功能,而不是使用非服务特定库的要求。Google 的问题跟踪器是开发人员报告问题并为其开发服务提出功能请求的地方。提交 Drive API 功能请求的页面位于此处。
差异注意: Drive API V2 中的调用Drive.Files.Insert已更改为Drive.Files.CreateDrive API V3 中的调用。
| 归档时间: |
|
| 查看次数: |
2181 次 |
| 最近记录: |