使用 Google 驱动器 API 将文件上传到 Google 驱动器时出现 OutOfMemoryException
OutOfMemoryException when upload file to Google Drive using Google Drive API
这是一个网站 application.I 正在尝试使用 GoogleDrive API 将大文件上传到 Google Drive。我的代码适用于较小的文件。但是当涉及到较大的文件时会发生错误。
我搜索了很多,但找不到工作的解决方案和一些没有答案的步骤。
文件转byte[]的代码部分出错。
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>");
}
}
}
我承认我不知道 GoogleDrive API,但您的代码似乎复杂得令人难以置信。为什么要进行反射,为什么要对每个文件进行反射?为什么将整个文件加载到字节数组中只是为了将其放入 MemoryStream
中,而当您从一开始就可以使用 FileStream
时,这不会将整个文件复制到内存中?
我认为您需要简化代码。所有的反射?编写您想要 编写的实际两行代码。然后使用文件流作为 InputStream.
您似乎想将所有文件放入一个请求中。 API 似乎希望您在一个请求中容纳一个文件。也许你应该这样做。
根据 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 位上。
这是一个网站 application.I 正在尝试使用 GoogleDrive API 将大文件上传到 Google Drive。我的代码适用于较小的文件。但是当涉及到较大的文件时会发生错误。
我搜索了很多,但找不到工作的解决方案和一些没有答案的步骤。
文件转byte[]的代码部分出错。
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>");
}
}
}
我承认我不知道 GoogleDrive API,但您的代码似乎复杂得令人难以置信。为什么要进行反射,为什么要对每个文件进行反射?为什么将整个文件加载到字节数组中只是为了将其放入 MemoryStream
中,而当您从一开始就可以使用 FileStream
时,这不会将整个文件复制到内存中?
我认为您需要简化代码。所有的反射?编写您想要 编写的实际两行代码。然后使用文件流作为 InputStream.
您似乎想将所有文件放入一个请求中。 API 似乎希望您在一个请求中容纳一个文件。也许你应该这样做。
根据 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 位上。