2016-06-07 17 views
0

Dies ist eine Webanwendung.Ich bin gerade dabei, große Dateien mit Google Drive API auf Google Drive hochzuladen. Mein Code funktioniert gut mit kleineren Dateien. Aber wenn es um größere Dateien geht, tritt ein Fehler auf.OutOfMemoryException beim Hochladen von Dateien in Google Drive mit der Google Drive-API

Ich hatte viel zu suchen, konnte aber keine Lösung für die Arbeit und einige der Lauffläche finden, die keine Antwort haben.

Fehler tritt in dem Codeteil auf, in dem die Datei in Byte [] konvertiert wird.

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

Für web.config Ich hatte versucht, die Anfrage Länge zu ändern, aber es nicht für eine großen Dateien zu arbeiten.

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

Hat jemand eine Lösung dafür? Danke im Voraus!

Unten ist der vollständige Code.


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>"); 

     } 


    } 
} 

Antwort

0

auf MSDN Acording Sie kann Setup es bei web.config wie:

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

aber seine sagt:

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

so dass sie nicht auf 32-Bit arbeiten, was bedeutet, dass Sie auch Ihre ausführen müssen Pool auf 64-Bit.

ref: http://msdn.microsoft.com/en-us/library/hh285054.aspx

+0

Ich hatte dies eingestellt, aber es ist nicht Arbeit, hier ist die Art, wie ich http://postimg.org/image/7fk07kmsr/ – Mike

2

Ich gebe zu, ich weiß nicht, die Google Drive-API, aber Ihr Code scheint kompliziert unglaublich. Warum machst du überhaupt Reflektion und warum für jede Datei? Warum laden Sie Ihre ganze Datei in ein Byte-Array, nur um es in eine MemoryStream, wenn Sie eine FileStream von Anfang an, die nicht Ihre gesamte Datei in den Speicher kopieren?

Ich würde sagen, Sie müssen Ihren Code vereinfachen. All diese Reflexion? Schreibe die eigentlichen zwei Zeilen Code, den du schreiben willst wollen. Verwenden Sie dann einen Filestream als InputStream.

Sie scheinen alle Ihre Dateien in eine einzige Anfrage passen zu wollen. Die API scheint zu wollen, dass Sie eine einzelne Datei in eine Anfrage einfügen. Vielleicht solltest du das tun.

+0

Hallo, ich foreach jede Datei in einem Ordner, weil ich mehrere Datei in einem Ordner hochladen möchte. Für MemoryStream, dass nur ein Test, ich nicht gelöscht, das ist nicht in der Anwendung verwendet. Ich forage eine Datei, weil ich einen Namen und Daten für eine Datei erhalten möchte. – Mike

Verwandte Themen