Saturday, June 15, 2013

Byte array - OutOfMemory exception on large file download - fix



Issue:
‘Byte’ array length has limitations. Here we found max supported to be around 1.3 GB (varies based on processor and available RAM). If length is set beyond, it throws an ‘OutOfMemory’ exception.

Fix:
Check if file exceeds 1GB, if so a functionality that splits the ‘file stream’ in chunks of ‘Byte’ array which is then fed to the ‘Response.BinaryWrite’ sequentially is executed. Else you can also use 'httpResponse.TransmitFile' option.

Code:

                WebClient client = new WebClient();
                client.DownloadFile(url, path);

                CustomLogger.WriteInfo("Download", "Page_Load", "Completed 'client.DownloadFile'");
                fileStream = new FileStream(path, FileMode.Open);
                int fileLength = (int)fileStream.Length;
                CustomLogger.WriteInfo("Download", "Page_Load", "FileStreamSize:" + fileLength.ToString());

                httpResponse.ClearHeaders();
                httpResponse.Clear();

                httpResponse.ContentType = "application/octet-stream";
                httpResponse.AddHeader("Content-Transfer-Encoding", "binary");
                httpResponse.AddHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
                httpResponse.AddHeader("Content-Length", fileLength.ToString());

                //Handling Large files
                if (fileLength >= Constant.MaxFileSize) //MaxFileSize - 1073741824 or 1Gb
                {
                    CustomLogger.WriteInfo("Download", "Page_Load", "BinaryWrite multiple instance");
                    int bufferSize = Constant.MaxFileSize;
                    long filePos = fileStream.Length;
                    long mod = filePos / bufferSize;
                    long val = default(long);


                    for (int j = 0; j <= mod; j++)
                    {
                        byte[] buffer = null;
                        int bytesToRead = bufferSize;
                        if (j == mod)
                        {
                            int minusVal = default(int);
                            if (val == 0)
                                minusVal = (int)val + bytesToRead;
                            else
                                minusVal = (int)val;

                            long subVal = filePos - (minusVal);
                            buffer = new byte[(int)subVal];
                            bytesToRead = (int)subVal;
                        }
                        else
                        {
                            buffer = new byte[bufferSize];
                        }

                        val = fileStream.Seek(0, SeekOrigin.Current);
                        int bytesRead = fileStream.Read(buffer, 0, bytesToRead);
                        httpResponse.BinaryWrite(buffer);
                        httpResponse.Flush();
                    }
                }
                else
                {
                    CustomLogger.WriteInfo("Download", "Page_Load", "BinaryWrite single instance");
                    byte[] fl = default(byte[]);
                    fl = new byte[fileStream.Length];
                    fileStream.Read(fl, 0, fileLength);
                    httpResponse.BinaryWrite(fl);
                    httpResponse.Flush();
                }

                httpResponse.End();

No comments:

Post a Comment