SDK从OneDrive下载大文件

SDK从OneDrive下载大文件

本文介绍了使用Microsoft Graph SDK从OneDrive下载大文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用下面的Microsoft Graph调用从OneDrive下载文件:

I am trying to download files from OneDrive using below Microsoft Graph call:

using (var strm = await client.Drives[RemoteDriveId].Items[Id].Content.Request().GetAsync())
{
   byte[] byteBuffer = new byte[4096];
   filePath = System.IO.Path.Combine(folderPath, filename);
   using (System.IO.FileStream output = new FileStream(filePath, FileMode.Create))
   {
      int bytesRead = 0;
      do
      {
        bytesRead = contentStream.Read(byteBuffer, 0, byteBuffer.Length);
        if (bytesRead > 0)
        {
           output.Write(byteBuffer, 0, bytesRead);
        }
      }
      while (bytesRead > 0);
   }
}

上述代码的问题是,如果文件很大或网络速度很慢,则在完全下载文件之前,SDK中会引发请求超时异常.我想分块下载文件或增加超时时间.如何使用Microsoft graph SDK实现此目的?

The issue with above code is that if the file size is large or network is slow, request time out exception is thrown in the SDK before the file is completely downloaded. I would like to download the file in chunks or increase the timeout. How can I achieve this using Microsoft graph SDK?

推荐答案

您需要使用Range标头对下载进行分块.

You'll need to chunk the download with the Range header.

// Based on question by Pavan Tiwari, 11/26/2012, and answer by Simon Mourier
// https://stackoverflow.com/questions/13566302/download-large-file-in-small-chunks-in-c-sharp

const long DefaultChunkSize = 50 * 1024; // 50 KB, TODO: change chunk size to make it realistic for a large file.
long ChunkSize = DefaultChunkSize;
long offset = 0;         // cursor location for updating the Range header.
byte[] bytesInStream;                    // bytes in range returned by chunk download.

// Get the collection of drive items. We'll only use one.
IDriveItemChildrenCollectionPage driveItems = await graphClient.Me.Drive.Root.Children.Request().GetAsync();

foreach (var item in driveItems)
{
    // Let's download the first file we get in the response.
    if (item.File != null)
    {
        // We'll use the file metadata to determine size and the name of the downloaded file
        // and to get the download URL.
        var driveItemInfo = await graphClient.Me.Drive.Items[item.Id].Request().GetAsync();

        // Get the download URL. This URL is preauthenticated and has a short TTL.
        object downloadUrl;
        driveItemInfo.AdditionalData.TryGetValue("@microsoft.graph.downloadUrl", out downloadUrl);

        // Get the number of bytes to download. calculate the number of chunks and determine
        // the last chunk size.
        long size = (long)driveItemInfo.Size;
        int numberOfChunks = Convert.ToInt32(size / DefaultChunkSize);
        // We are incrementing the offset cursor after writing the response stream to a file after each chunk.
        // Subtracting one since the size is 1 based, and the range is 0 base. There should be a better way to do
        // this but I haven't spent the time on that.
        int lastChunkSize = Convert.ToInt32(size % DefaultChunkSize) - numberOfChunks - 1;
        if (lastChunkSize > 0) { numberOfChunks++; }

        // Create a file stream to contain the downloaded file.
        using (FileStream fileStream = System.IO.File.Create((@"C:\Temp\" + driveItemInfo.Name)))
        {
            for (int i = 0; i < numberOfChunks; i++)
            {
                // Setup the last chunk to request. This will be called at the end of this loop.
                if (i == numberOfChunks - 1)
                {
                    ChunkSize = lastChunkSize;
                }

                // Create the request message with the download URL and Range header.
                HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Get, (string)downloadUrl);
                req.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(offset, ChunkSize + offset);

                // We can use the the client library to send this although it does add an authentication cost.
                // HttpResponseMessage response = await graphClient.HttpProvider.SendAsync(req);
                // Since the download URL is preauthenticated, and we aren't deserializing objects,
                // we'd be better to make the request with HttpClient.
                var client = new HttpClient();
                HttpResponseMessage response = await client.SendAsync(req);

                using (Stream responseStream = await response.Content.ReadAsStreamAsync())
                {
                    bytesInStream = new byte[ChunkSize];
                    int read;
                    do
                    {
                        read = responseStream.Read(bytesInStream, 0, (int)bytesInStream.Length);
                        if (read > 0)
                            fileStream.Write(bytesInStream, 0, bytesInStream.Length);
                    }
                    while (read > 0);
                }
                offset += ChunkSize + 1; // Move the offset cursor to the next chunk.
            }
        }
        return;
    }
}

这篇关于使用Microsoft Graph SDK从OneDrive下载大文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-11 19:00