Чтение больших файлов - 2 ГБ + для загрузки Google Drive API - PullRequest
1 голос
/ 28 мая 2020

В настоящее время я работаю над небольшим инструментом резервного копирования, написанным на C#, который должен загружать файлы, содержащиеся в указанной папке, на Google Диск через его API. Программа в основном работает так, как предполагалось, единственная проблема заключается в том, что она не может обрабатывать файлы размером более 2 ГБ.

Проблема вызвана самой функцией загрузки, которая прикреплена ниже, она использует массив байтов для прочтите файл, чтобы впоследствии создать поток памяти. Насколько мне известно (я все еще новичок, когда дело доходит до c#), байтовый массив может содержать только 2 ГБ информации перед возвратом исключения переполнения. Для борьбы с этим я попытался использовать FileStream.Read (второй фрагмент кода, прилагаемый ниже) вместо System.IO.File.ReadAllBytes, хотя это снова привело к исключению переполнения байтового массива. Я знаю, что на этом этапе мне придется разделить файл на части из-за довольно ограниченной документации API GDrive для C# - по крайней мере, из того, что я видел - и моих ограниченных знаний о C# Я почти не понимаю, как решить эту проблему.

Прошу прощения за долгое чтение, вся помощь по этому вопросу приветствуется.

Функция загрузки V1 (System.IO.File.ReadAllBytes):

    private static Google.Apis.Drive.v3.Data.File UploadFile(Boolean useFolder, String mime, DriveService _service, string _uploadFile, string _parent, string _descrp = "")
    {
        if (System.IO.File.Exists(_uploadFile))
        {
            Google.Apis.Drive.v3.Data.File body = new Google.Apis.Drive.v3.Data.File
            {
                Name = System.IO.Path.GetFileName(_uploadFile),
                Description = _descrp,
                MimeType = mime
            };
            if (useFolder)
            {
                body.Parents = new List<string> { _parent };
            }
            byte[] byteArray = System.IO.File.ReadAllBytes(_uploadFile);
            MemoryStream stream = new System.IO.MemoryStream(byteArray);
            try
            {
                FilesResource.CreateMediaUpload request = _service.Files.Create(body, stream, mime);
                request.SupportsTeamDrives = true;
                request.Upload();
                return request.ResponseBody;
            }
            catch (Exception e)
            {
                Console.WriteLine("Error Occured: " + e);
                return null;
            }
        }
        else
        {
            Console.WriteLine("The file does not exist. 404");
            return null;
        }
    }

Метод загрузки V2 (FileStream):

    private static Google.Apis.Drive.v3.Data.File UploadFile(Boolean useFolder, String mime, DriveService _service, string _uploadFile, string _parent, string _descrp = "")
    {
        if (System.IO.File.Exists(_uploadFile))
        {
            Google.Apis.Drive.v3.Data.File body = new Google.Apis.Drive.v3.Data.File
            {
                Name = System.IO.Path.GetFileName(_uploadFile),
                Description = _descrp,
                MimeType = mime
            };
            if (useFolder)
            {
                body.Parents = new List<string> { _parent };
            }
            //byte[] byteArray = System.IO.File.ReadAllBytes(_uploadFile);
            using (FileStream fileStream = new FileStream(_uploadFile, FileMode.Open, FileAccess.Read))
            {
                Console.WriteLine("ByteArrayStart");
                byte[] byteArray = new byte[fileStream.Length];
                int bytesToRead = (int)fileStream.Length;
                int bytesRead = 0;
                while (bytesRead > 0)
                {
                    int n = fileStream.Read(byteArray, bytesRead, bytesToRead);
                    if (n == 0)
                    {
                        break;
                    }
                    bytesRead += n;
                    Console.WriteLine("Bytes Read: " + bytesRead);
                    bytesToRead -= n;
                    Console.WriteLine("Bytes to Read: " + bytesToRead);
                }
                bytesToRead = byteArray.Length;
                MemoryStream stream = new System.IO.MemoryStream(byteArray);
                try
                {
                    FilesResource.CreateMediaUpload request = _service.Files.Create(body, stream, mime);
                    request.SupportsTeamDrives = true;
                    request.Upload();
                    return request.ResponseBody;
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error Occured: " + e);
                    return null;
                }
            }
        }
        else
        {
            Console.WriteLine("The file does not exist. 404");
            return null;
        }
    }

1 Ответ

4 голосов
/ 28 мая 2020
Конструкторы

MemoryStream работают только с массивами байтов, размер которых ограничен Int32.MaxValue байтами. Почему бы просто не использовать ваш объект FileStream напрямую?

var fileMetadata = new Google.Apis.Drive.v3.Data.File()
{
    Name = "flag.jpg"
};

FilesResource.CreateMediaUpload request;
using (var stream = new System.IO.FileStream(@"C:\temp\flag.jpg", System.IO.FileMode.Open))
{
    request = service.Files.Create(fileMetadata, stream, "image/jpeg");
    request.Fields = "id";
    request.Upload();
}
var file = request.ResponseBody;

На самом деле файл такого размера, который вы должны использовать для возобновляемой загрузки, но мне придется копаться в поисках некоторого образца кода для этого.

...