2016-06-07 2 views
0

Это веб-приложение. Я связываю загрузку больших файлов на Google Диск с помощью API GoogleDrive. Мой код отлично работает с меньшими файлами. Но когда дело доходит до больших файлов, возникает ошибка.OutOfMemoryException при загрузке файла на Google Диск с использованием API Диска Google

У меня был поиск много, но не удалось найти решение для работы и некоторые протекторы, у которых нет ответа.

Ошибка в части кода, в которой файл преобразуется в байт [].

byte[] fileData = System.IO.File.ReadAllBytes(dir); 

Для web.config Я пытаюсь изменить длину запроса, но она не работает для больших файлов.

<httpRuntime targetFramework="4.5" executionTimeout="520000" maxRequestLength="920000" /> 

У кого-нибудь есть решение для этого? Заранее спасибо!

Ниже приведен полный код.


using System; 
using System.Diagnostics; 
using DotNetOpenAuth.OAuth2; 
using Google.Apis.Authentication.OAuth2; 
using Google.Apis.Authentication.OAuth2.DotNetOpenAuth; 
using Google.Apis.Drive.v2; 
using Google.Apis.Drive.v2.Data; 
using Google.Apis.Util; 
using ASPSnippets.GoogleAPI; 
using System.Web.Script.Serialization; 
using System.Web; 
using System.Collections.Generic; 
using System.Net.Http; 
using System.Net; 
using System.IO; 
using System.Reflection; 

namespace GoogleDriveAutoUpdate 
{ 
    public partial class GoogleDriveSample : System.Web.UI.Page 
    { 
     static int flagUpdateFile; 
     protected string[] dirs = Directory.GetFiles(@"C:\Users\RNKP74\Desktop\GoogleDrive"); 


     protected void Page_Load(object sender, EventArgs e) 
     { 
      GoogleConnect.ClientId = ""; 
      GoogleConnect.ClientSecret = ""; 
      GoogleConnect.RedirectUri = Request.Url.AbsoluteUri.Split('?')[0]; 
      GoogleConnect.API = EnumAPI.Drive; 

      if (string.IsNullOrEmpty(Request.QueryString["code"])) 
       GoogleConnect.Authorize("https://www.googleapis.com/auth/drive.file"); 

      if (flagUpdateFile == 0) 
       UploadFile(); 
     } 

     protected HttpPostedFile ConstructHttpPostedFile(byte[] data, string filename, string contentType = null) 
     { 
      // Get the System.Web assembly reference 
      Assembly systemWebAssembly = typeof(HttpPostedFileBase).Assembly; 
      // Get the types of the two internal types we need 
      Type typeHttpRawUploadedContent = systemWebAssembly.GetType("System.Web.HttpRawUploadedContent"); 
      Type typeHttpInputStream = systemWebAssembly.GetType("System.Web.HttpInputStream"); 

      // Prepare the signatures of the constructors we want. 
      Type[] uploadedParams = { typeof(int), typeof(int) }; 
      Type[] streamParams = { typeHttpRawUploadedContent, typeof(int), typeof(int) }; 
      Type[] parameters = { typeof(string), typeof(string), typeHttpInputStream }; 

      // Create an HttpRawUploadedContent instance 
      object uploadedContent = typeHttpRawUploadedContent 
       .GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, uploadedParams, null) 
       .Invoke(new object[] { data.Length, data.Length }); 

      // Call the AddBytes method 
      typeHttpRawUploadedContent 
       .GetMethod("AddBytes", BindingFlags.NonPublic | BindingFlags.Instance) 
       .Invoke(uploadedContent, new object[] { data, 0, data.Length }); 

      // This is necessary if you will be using the returned content (ie to Save) 
      typeHttpRawUploadedContent 
       .GetMethod("DoneAddingBytes", BindingFlags.NonPublic | BindingFlags.Instance) 
       .Invoke(uploadedContent, null); 

      // Create an HttpInputStream instance 
      object stream = (Stream)typeHttpInputStream 
       .GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, streamParams, null) 
       .Invoke(new object[] { uploadedContent, 0, data.Length }); 

      // Create an HttpPostedFile instance 
      HttpPostedFile postedFile = (HttpPostedFile)typeof(HttpPostedFile) 
       .GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, parameters, null) 
       .Invoke(new object[] { filename, contentType, stream }); 

      return postedFile; 
     } 

     protected void UploadFile() 
     { 
      int successCount = 0; 
      HttpFileCollection MyFileCollection = Request.Files; 
      Response.Write("Total number file = " + dirs.Length + "<br/>"); 

      foreach (string dir in dirs) 
      { 

       byte[] fileData = System.IO.File.ReadAllBytes(dir); 
       string fileName = Path.GetFileName(dir); 
       flagUpdateFile = 1; 
       //Content Type is null 
       Session["File"] = ConstructHttpPostedFile(fileData, fileName); 

       //Token return from Google API 
       if (!string.IsNullOrEmpty(Request.QueryString["code"]) && flagUpdateFile == 1) 
       { 
        string code = Request.QueryString["code"]; 
        string json = GoogleConnect.PostFile(code, (HttpPostedFile)Session["File"], ""); 
        flagUpdateFile = 0; 
        System.IO.File.Delete(dir); 
        successCount++; 
       } 

       if (Request.QueryString["error"] == "access_denied") 
       { 
        ClientScript.RegisterClientScriptBlock(this.GetType(), "alert", "alert('Access denied.')", true); 
        Console.Write("Access denied,check your Authorized redirect URIs!"); 
       } 

       HttpContext.Current.Session.Remove("File"); 
       HttpContext.Current.Session.Abandon(); 

      } 
      Response.Write("Total file uploaded = " + successCount); 
      successCount = 0; 
      Response.Write("<span id='Label1' style='color:red'><br/>Sucess if the number is identical</span>"); 

     } 


    } 
} 

ответ

0

Acording в MSDN вы можете настроить ее по крайней web.config как:

<configuration> 
    <runtime> 
    <gcAllowVeryLargeObjects enabled="true" /> 
    </runtime> 
</configuration> 

но его говорит:

true: Arrays greater than 2 GB in total size are enabled on 64-bit platforms. 

поэтому его не работает на 32-битной, а это означает, что вы должны запустить свой пул на 64-бит.

исх: http://msdn.microsoft.com/en-us/library/hh285054.aspx

+0

Я установил это, но это не работает, вот как я установил http://postimg.org/image/7fk07kmsr/ – Mike

2

Я признаю, что я не знаю GoogleDrive API, но ваш код кажется невероятно сложным. Почему вы вообще размышляете и почему для каждого файла? Почему вы загружаете весь свой файл в байтовый массив, чтобы поместить его в MemoryStream, когда вы можете с самого начала использовать FileStream, который не копирует весь ваш файл в память?

Я бы сказал, что вам нужно упростить свой код. Все это Отражение? Напишите фактические две строки кода: хочу написать. Затем используйте filestream как InputStream.

Кажется, что вы хотите, чтобы все ваши файлы были помещены в один запрос. Кажется, что API хочет, чтобы вы поместили один файл в один запрос. Может быть, вы должны это сделать.

+0

Привет, я Foreach каждый файл на папку, потому что я хочу, чтобы загрузить несколько файлов в папке. Для MemoryStream, который просто тестирует, я не удаляю, что не используется в приложении. Я хочу получить файл, потому что хочу получить имя и данные для файла. – Mike