gpt4 book ai didi

C# - 以字节 block 的形式从 Google Drive 下载

转载 作者:可可西里 更新时间:2023-11-01 08:11:27 26 4
gpt4 key购买 nike

我目前正在为网络连接不佳的环境进行开发。我的应用程序有助于自动为用户下载所需的 Google 云端硬盘文件。它适用于小文件(从 40KB 到 2MB),但对于较大的文件(9MB)却经常失败。我知道这些文件大小可能看起来很小,但就我客户的网络环境而言,Google Drive API 经常因 9MB 文件而失败。

我已经得出结论,我需要以较小的字节 block 下载文件,但我不知道如何使用 Google Drive API 来做到这一点。我读过 this一遍又一遍,我尝试了以下代码:

// with the Drive File ID, and the appropriate export MIME type, I create the export request
var request = DriveService.Files.Export(fileId, exportMimeType);

// take the message so I can modify it by hand
var message = request.CreateRequest();
var client = request.Service.HttpClient;

// I change the Range headers of both the client, and message
client.DefaultRequestHeaders.Range =
message.Headers.Range =
new System.Net.Http.Headers.RangeHeaderValue(100, 200);
var response = await request.Service.HttpClient.SendAsync(message);

// if status code = 200, copy to local file
if (response.IsSuccessStatusCode)
{
using (var fileStream = new FileStream(downloadFileName, FileMode.CreateNew, FileAccess.ReadWrite))
{
await response.Content.CopyToAsync(fileStream);
}
}

然而,生成的本地文件(来自 fileStream)仍然是全长的(即 ​​40KB 驱动器文件为 40KB 文件,9MB 文件为 500 内部服务器错误)。在旁注中,我还尝试了 ExportRequest.MediaDownloader.ChunkSize,但据我观察,它只会改变 ExportRequest.MediaDownloader.ProgressChanged 回调的频率调用(即,如果 ChunkSize 设置为 256 * 1024,回调将每 256KB 触发一次)。

我该如何继续?

最佳答案

您似乎正朝着正确的方向前进。根据您上次的评论,该请求将根据 block 大小更新进度,因此您的观察是准确的。

调查 source code for MediaDownloader in the SDK发现以下(强调我的)

The core download logic. We download the media and write it to an output stream ChunkSize bytes at a time, raising the ProgressChanged event after each chunk. The chunking behavior is largely a historical artifact: a previous implementation issued multiple web requests, each for ChunkSize bytes. Now we do everything in one request, but the API and client-visible behavior are retained for compatibility.

您的示例代码只会下载 100 到 200 之间的一个 block 。使用这种方法,您必须跟踪索引并手动下载每个 block ,将它们复制到文件流中以供每次部分下载

const int KB = 0x400;
int ChunkSize = 256 * KB; // 256KB;
public async Task ExportFileAsync(string downloadFileName, string fileId, string exportMimeType) {

var exportRequest = driveService.Files.Export(fileId, exportMimeType);
var client = exportRequest.Service.HttpClient;

//you would need to know the file size
var size = await GetFileSize(fileId);

using (var file = new FileStream(downloadFileName, FileMode.CreateNew, FileAccess.ReadWrite)) {

file.SetLength(size);

var chunks = (size / ChunkSize) + 1;
for (long index = 0; index < chunks; index++) {

var request = exportRequest.CreateRequest();

var from = index * ChunkSize;
var to = from + ChunkSize - 1;

request.Headers.Range = new RangeHeaderValue(from, to);

var response = await client.SendAsync(request);

if (response.StatusCode == HttpStatusCode.PartialContent || response.IsSuccessStatusCode) {
using (var stream = await response.Content.ReadAsStreamAsync()) {
file.Seek(from, SeekOrigin.Begin);
await stream.CopyToAsync(file);
}
}
}
}
}

private async Task<long> GetFileSize(string fileId) {
var file = await driveService.Files.Get(fileId).ExecuteAsync();
var size = file.size;
return size;
}

此代码对驱动器 api/服务器做了一些假设。

  • 服务器将允许分块下载文件所需的多个请求。不知道请求是否受到限制。
  • 服务器仍然接受开发者文档中所述的 Range header

关于C# - 以字节 block 的形式从 Google Drive 下载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38449621/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com