Microsoft Graph DriveItem 内容流?
Microsoft Graph DriveItem Content Stream?
我希望能够使用 Graph 下载大文件。为此,我需要将文件“分块”,因为它太大而无法放入可用内存。不幸的是,我知道的唯一调用是立即将整个文件读入内存。有没有办法避免这种情况?我应该使用什么电话?
我正在使用的电话是:
graphClient.Drives[driveId].Items[itemId].Content.Request().GetAsync()
我想使用具有缓冲区大小的“CopyToAsync”将此流发送到我的响应流,但它在我可以之前因内存异常而爆炸。据说在实际的 REST 调用中有一个“范围”选项,但我还没有想出在使用“GraphServiceClient”时如何使用它。
如有任何帮助,我们将不胜感激!
您可以获得文件的下载 URL 并分块下载。
获取 DriveItem
并从元数据中读取 downloadUrl, size
。使用 downloaUrl
和 Range
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;
}
}
我希望能够使用 Graph 下载大文件。为此,我需要将文件“分块”,因为它太大而无法放入可用内存。不幸的是,我知道的唯一调用是立即将整个文件读入内存。有没有办法避免这种情况?我应该使用什么电话?
我正在使用的电话是:
graphClient.Drives[driveId].Items[itemId].Content.Request().GetAsync()
我想使用具有缓冲区大小的“CopyToAsync”将此流发送到我的响应流,但它在我可以之前因内存异常而爆炸。据说在实际的 REST 调用中有一个“范围”选项,但我还没有想出在使用“GraphServiceClient”时如何使用它。
如有任何帮助,我们将不胜感激!
您可以获得文件的下载 URL 并分块下载。
获取 DriveItem
并从元数据中读取 downloadUrl, size
。使用 downloaUrl
和 Range
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;
}
}