C#-以字节块形式从谷歌硬盘下载

C#-以字节块形式从谷歌硬盘下载,c#,.net,rest,google-drive-api,C#,.net,Rest,Google Drive Api,我目前正在为网络连接不良的环境开发。我的应用程序帮助用户自动下载所需的Google Drive文件。它对于小文件(从40KB到2MB)工作得相当好,但对于大文件(9MB)却常常失败。我知道这些文件的大小可能看起来很小,但就我客户的网络环境而言,GoogleDriveAPI经常出现9MB文件的故障 我已经得出结论,我需要下载较小字节块的文件,但我不知道如何使用GoogleDriveAPI实现这一点。我反复阅读了一遍,并尝试了以下代码: // with the Drive File ID, and

我目前正在为网络连接不良的环境开发。我的应用程序帮助用户自动下载所需的Google Drive文件。它对于小文件(从40KB到2MB)工作得相当好,但对于大文件(9MB)却常常失败。我知道这些文件的大小可能看起来很小,但就我客户的网络环境而言,GoogleDriveAPI经常出现9MB文件的故障

我已经得出结论,我需要下载较小字节块的文件,但我不知道如何使用GoogleDriveAPI实现这一点。我反复阅读了一遍,并尝试了以下代码:

// 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触发一次)


我该怎么办呢?

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

在调查中发现了以下内容(强调我的)

核心下载逻辑。我们下载媒体并将其写入 每次输出流ChunkSize字节,提高进程 每个区块后的事件。分块行为在很大程度上是一种历史现象 工件:以前的实现发出了多个web请求,每个请求 对于ChunkSize字节。现在我们在一个请求中做所有事情,但是API 并保留客户端可见行为以实现兼容性

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

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;
}
const int KB=0x400;
int ChunkSize=256*KB;//256KB;
公共异步任务ExportFileAsync(字符串下载文件名、字符串文件ID、字符串exportMimeType){
var exportRequest=driveService.Files.Export(fileId,exportMimeType);
var client=exportRequest.Service.HttpClient;
//您需要知道文件大小
var size=await-GetFileSize(fileId);
使用(var file=new FileStream(下载文件名,FileMode.CreateNew,FileAccess.ReadWrite)){
file.SetLength(大小);
var chunks=(size/ChunkSize)+1;
for(长索引=0;索引<块;索引++){
var request=exportRequest.CreateRequest();
var from=索引*块大小;
var to=from+ChunkSize-1;
request.Headers.Range=新的RangeHeaderValue(从,到);
var response=wait client.sendaync(请求);
if(response.StatusCode==HttpStatusCode.PartialContent | | response.issuccesstatuscode){
使用(var stream=await response.Content.ReadAsStreamAsync()){
Seek(from,SeekOrigin.Begin);
等待stream.CopyToAsync(文件);
}
}
}
}
}
专用异步任务GetFileSize(字符串文件ID){
var file=wait driveService.Files.Get(fileId.ExecuteAsync();
var size=file.size;
返回大小;
}
这段代码对驱动器api/服务器进行了一些假设

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

您是否尝试过使用类似的代理检查请求/响应?我会仔细检查我的客户是否以我希望的方式发送范围标头。此外,msdn博客文章——看起来有点帮助(即使它是以服务器为中心的),并指出如果a)您发送了正确的请求,并且b)服务器支持范围标头,则应该使用206返回码,而不是200返回码。也就是说,看起来你正朝着正确的方向前进。@matt,你解决过这个问题吗?@Nkosi很抱歉现在才回复,我最终放弃了这个项目,所以我从来没有解决过。如果你(或任何与此相关的人)找到了解决方案,请将其作为答案发布!