Microsoft Graph DriveItem 内容流?

Microsoft Graph DriveItem Content Stream?

我希望能够使用 Graph 下载大文件。为此,我需要将文件“分块”,因为它太大而无法放入可用内存。不幸的是,我知道的唯一调用是立即将整个文件读入内存。有没有办法避免这种情况?我应该使用什么电话?

我正在使用的电话是:

graphClient.Drives[driveId].Items[itemId].Content.Request().GetAsync()

我想使用具有缓冲区大小的“CopyToAsync”将此流发送到我的响应流,但它在我可以之前因内存异常而爆炸。据说在实际的 REST 调用中有一个“范围”选项,但我还没有想出在使用“GraphServiceClient”时如何使用它。

如有任何帮助,我们将不胜感激!

您可以获得文件的下载 URL 并分块下载。

获取 DriveItem 并从元数据中读取 downloadUrl, size。使用 downloaUrlRange header 指定要下载的字节范围。

private async Task DonwloadLargeFile()
{
    long defaultChunkSize = 50 * 1024;

    var driveItem = await client.Drives["driveId"].Items["itemId"].Request().GetAsync();
        
    driveItem.AdditionalData.TryGetValue("@microsoft.graph.downloadUrl", out var downloadUrl);

    var size = (long)driveItem.Size;
    var numberOfChunks = Convert.ToInt32(size / defaultChunkSize);
    var lastChunkSize = Convert.ToInt32(size % defaultChunkSize) - numberOfChunks - 1;
    if (lastChunkSize > 0) 
    { 
        numberOfChunks++; 
    }

    using (var fs = System.IO.File.Create(Path.Combine(@"C:\Download",driveItem.Name)))
    {
        var chunkSize = defaultChunkSize;
        long offset = 0;
        byte[] buffer;
        for (int i = 0; i < numberOfChunks; i++)
        {
            if (i == numberOfChunks - 1)
            {
                chunkSize = lastChunkSize;
            }

            var req = new HttpRequestMessage(HttpMethod.Get, (string)downloadUrl);
            req.Headers.Range = new RangeHeaderValue(offset, chunkSize + offset);

            var response = await client.HttpProvider.SendAsync(req);
            using (var rs = await response.Content.ReadAsStreamAsync())
            {
                buffer = new byte[chunkSize];
                int read;
                do
                {
                    read = rs.Read(buffer, 0, buffer.Length);
                    if (read > 0)
                    {
                        fs.Write(buffer, 0, buffer.Length);
                    }
                }
                while (read > 0);
            }
            offset += chunkSize + 1;
        }
    }
}

@user2250152 提供的答案很好,让我走上了正确的轨道,但代码本身需要一些改进。这是我正在使用的:

private async Task GetLargeFileAsync(GraphServiceClient graphClient, string driveId, string itemId, long defaultChunkSize, HttpResponse response)
{
    var driveItem = await graphClient.Drives[driveId].Items[itemId].Request().GetAsync();
    driveItem.AdditionalData.TryGetValue("@microsoft.graph.downloadUrl", out var downloadUrl);

    var size = (long)driveItem.Size;
    response.ContentLength = size;

    long offset = 0;
    while (offset < size)
    {
        var chunkSize = Math.Min(size - offset, defaultChunkSize);
        var req = new HttpRequestMessage(HttpMethod.Get, downloadUrl.ToString());
        req.Headers.Range = new RangeHeaderValue(offset, chunkSize + offset - 1);

        var graphClientResponse = await graphClient.HttpProvider.SendAsync(req);
        using (var rs = await graphClientResponse.Content.ReadAsStreamAsync())
        {
            await rs.CopyToAsync(response.Body);
        }
        offset += defaultChunkSize;
    }
}