兩周前就想把這點經驗記錄下來了,由於拖延症上身,直到剛才突然想起這件未完成的任務,今天是1024,在這個特別的日子里,祝所有程序猿兄弟姐妹們節日快樂!
上傳功能一直很正常,直到上傳了個500多兆的文件,報錯提示:
“System.OutOfMemoryException”類型的異常在 mscorlib.dll 中發生,但未在用戶代碼中進行處理
對於內部用途和新的托管對象,確保要有足夠的內存可供分配。
如果要創建數組,請確保大小正確。
由於調用的webservice中的文件上傳方法參數為二進制格式,需要把文件流轉換為byte格式,所以直接寫了byte[] byte = new byte[stream.Length],結果那個大文件就是在這句卡住了,一開始也很蒙圈,已經在配置文件中修改了最大請求的長度為何還會有問題,調試代碼發現new byte[]的時候括號內要求參數是一個8位的整數,那個500多兆的文件轉為字節后是個9位數,導致byte類型超出索引,於是想到每次實例化一個固定長度的byte,讓文件循環寫入,寫滿一個byte就放入數組,然后在服務端在解析這個數組即可,這樣就不會存在內存溢出的問題了,下面是示例代碼,僅供參考,若要帶走,歡迎轉發。
腳本部分在上一篇中有代碼展示,這里只展示后台和服務端代碼了。
1.一般處理程序部分:
public void FileUpload(HttpContext context) { WebService ws = new WebService(); ws.Timeout = 3600000; //單位毫秒,1小時 HttpFileCollection files = context.Request.Files; if (files.Count > 0) { /*獲取真實文件名,files[0].FileName這種方法在IE瀏覽器中上傳會帶有F://路徑*/ string filename = System.IO.Path.GetFileName(files[0].FileName); HttpPostedFile file = files[0]; Stream fs = file.InputStream; /*定義object數組,用來存放byte數據*/ object[] obj = new object[] { }; List<object> list = new List<object>(); int offcount = 1048576; /* size:1M,unit:byte */ int LimitSize = 157286400;/*限制大小150M,unit:byte*/ if (fs.Length > LimitSize) { context.Response.Write("OutOfSize"); context.Response.End(); return; } int filelen = (int)fs.Length; if (filelen > offcount) { long offset = 0; byte[] postArray = new byte[offcount]; int temponum = filelen / offcount; /*整數部分*/ for (int i = 1; i <= temponum; i++) { long lkl = filelen; postArray = new byte[offcount]; fs.Seek(offset, SeekOrigin.Begin); fs.Read(postArray, 0, offcount); list.Add(postArray); offset += offcount; } /*剩余部分*/ if (temponum * offcount < filelen) { offcount = filelen - temponum * offcount; byte[] lpostArray = new byte[offcount]; fs.Seek(offset, SeekOrigin.Begin); fs.Read(lpostArray, 0, offcount); list.Add(lpostArray); } } else { byte[] postArray = new byte[file.ContentLength]; fs.Read(postArray, 0, file.ContentLength); list.Add(postArray); } /*list集合轉為object數組*/ obj = list.ToArray(); fs.Flush(); fs.Close(); /*計算文件大小,文件大於1M,單位用M,其他用KB*/ string filesize = string.Empty; if (filelen > 1048576) { filesize = Math.Ceiling((double)filelen / (double)1024 / (double)1024) + "M"; } else { filesize = Math.Ceiling((double)filelen / (double)1024) + "KB"; } /*為防止流長度溢出byte,固定byte大小放入object數組*/ string result = ws.objUploadFile(obj, "FileFolder", filename); } }
2.webservice服務端部分:
/// <summary> /// 上傳文件 /// </summary> /// <param name="obj">分割的byte[]數組</param> /// <param name="path">文件存放文件夾</param> /// <param name="fileName">文件名字</param> /// <returns>文件的路徑</returns> [WebMethod(Description = "上傳文件,返回路徑")] public string objUploadFile(object[] obj, string path, string fileName) { string ReturnPath = string.Empty; FileStream wf = null; byte[] fs; try { string _FileName = string.Empty; string FilePath = "uploadfiles\\document\\" + path; FilePath = Server.MapPath(FilePath); if (!Directory.Exists(FilePath)) { Directory.CreateDirectory(FilePath); } System.Random rnd = new System.Random(); string tmp = rnd.Next(999999999).ToString(); _FileName = "File_" + tmp + "_" + fileName; //文件名加隨機數字 wf = new FileStream(FilePath + "\\" + _FileName, FileMode.Append, FileAccess.Write); if (obj.Length > 0) { for (int i = 0; i < obj.Length; i++) { fs = (byte[])obj[i]; wf.Write(fs, 0, fs.Length); } } wf.Close(); wf = null; ReturnPath = "\\uploadfiles\\document\\" + path + "\\" + _FileName; } catch { ReturnPath = string.Empty; } finally { } return ReturnPath; }
希望本文能夠幫助遇到同樣問題的同學們,如有不妥之處,歡迎指正。