Ответ 1
Вы, казалось, направлялись в правильном направлении. Начиная с вашего последнего комментария, запрос будет обновлять прогресс, основанный на размере куска, поэтому ваше наблюдение было точным.
Заглянув в исходный код для MediaDownloader
в SDK, было найдено следующее: (выделено мной)
Основная логика загрузки. Мы загружаем носители и записываем их в выходной поток ChunkSize байтов за раз, повышение ProgressChanged событие после каждого фрагмента. Поведение в целом является историческим артефакт: предыдущая реализация выдавала несколько веб-запросов, каждая для байтов 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;
}
Этот код делает некоторые предположения о диске api/server.
- Чтобы сервер разрешил несколько запросов, необходимых для загрузки файла в куски. Не знаю, запущены ли запросы.
- Чтобы сервер по-прежнему принимал заголовок
Range
, как указано в документе documenation разработчика