【问题标题】:Read large files - 2GB+ for Google Drive API Upload读取大文件 - 2GB+ 用于 Google Drive API 上传
【发布时间】:2020-09-16 07:44:52
【问题描述】:

我目前正在开发一个用 C# 编写的小型备份工具,该工具应该通过其 API 将指定文件夹中包含的文件上传到 Google Drive。该程序在很大程度上按预期运行,唯一的问题是它无法处理大于 2GB 的文件。

这个问题是由上传函数本身引起的,它附在下面,它使用一个字节数组来读取文件,然后创建一个内存流。据我所知(在 c# 方面我仍然是初学者),一个字节数组在返回溢出异常之前只能包含 2GB 的信息。为了解决这个问题,我尝试使用 FileStream.Read(下面附加的第二位代码)而不是 System.IO.File.ReadAllBytes,尽管这再次导致字节数组的溢出异常。我知道此时我必须拆分文件,但是,由于 C# 的 GDrive API 的文档相当有限 - 至少从我所见 - 以及我对 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;
        }
    }

【问题讨论】:

  • 只要你使用那个字节数组来表示整个文件,你就会遇到同样的问题。
  • 感谢您的快速回复。在这种情况下我可以改用什么建议?
  • 为什么不尝试将 FileStream 直接交给 Google API,而不是尝试通过 MemoryStream?
  • 它们都来自同一个Stream class
  • 我同意 - 您在代码中所做的实际上是打开流,然后将整个流复制到另一个流,然后将第二个流交给 Google File SDK。如果您只是打开一个FileStream 并将其提供给 SDK,它应该会正确执行所有操作。

标签: c# google-api google-drive-api google-api-dotnet-client


【解决方案1】:

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;

确实是一个那么大的文件,您应该使用可恢复上传,但我将不得不为此挖掘一些示例代码。

【讨论】:

  • 就是这样!我还在上传测试文件——但实际上它现在正在上传。这比我预期的要容易得多。谢谢!
猜你喜欢
  • 1970-01-01
  • 2018-08-06
  • 2017-02-17
  • 2014-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-10
  • 2017-09-17
相关资源
最近更新 更多