Арифметическая операция привела к переполнению ERROR - для массивов byte [] в c # - PullRequest
1 голос
/ 10 ноября 2011

У меня есть эта строка в c #:

    byte[] bytes = new byte[streamReader.BaseStream.Length];

Эта длина возвращает размер файла больше 4 ГБ.

в этой строке у меня ошибка ниже:

Arithmetic operation resulted in an overflow. 
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.OverflowException: Arithmetic operation resulted in an overflow.

Source Error: 


Line 41:             System.IO.BinaryReader br = new System.IO.BinaryReader(streamReader.BaseStream);
Line 42: 
Line 43:             byte[] bytes = new byte[streamReader.BaseStream.Length];
Line 44: 
Line 45:             br.Read(bytes, 0, (int)streamReader.BaseStream.Length);

как я могу исправить эту ошибку?

edit
я использую .net 4
, который был частью обработчика для загрузки файлов, как показано ниже:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using WindowsServer.Classes;

namespace WindowsServer
{
    /// <summary>
    /// Summary description for HandlerForMyFE
    /// </summary>
    public class Handler : IHttpHandler, System.Web.SessionState.IRequiresSessionState
    {

        private HttpContext _context;
        private HttpContext Context
        {
            get
            {
                return _context;
            }
            set
            {
                _context = value;
            }
        }

        public void ProcessRequest(HttpContext context)
        {
            Context = context;
            string filePath = context.Request.QueryString["Downloadpath"];
            filePath = context.Server.MapPath(filePath);

            if (filePath == null)
            {
                return;
            }

            System.IO.StreamReader streamReader = new System.IO.StreamReader(filePath);
            System.IO.BinaryReader br = new System.IO.BinaryReader(streamReader.BaseStream);

            byte[] bytes = new byte[streamReader.BaseStream.Length];

            br.Read(bytes, 0, (int)streamReader.BaseStream.Length);

            if (bytes == null)
            {
                return;
            }

            streamReader.Close();
            br.Close();
            string fileName = System.IO.Path.GetFileName(filePath);
            string MimeType = GetMimeType(fileName);
            string extension = System.IO.Path.GetExtension(filePath);
            char[] extension_ar = extension.ToCharArray();
            string extension_Without_dot = string.Empty;
            for (int i = 1; i < extension_ar.Length; i++)
            {
                extension_Without_dot += extension_ar[i];
            }

            string filesize = string.Empty;
            FileInfo f = new FileInfo(filePath);
            filesize = f.Length.ToString();

            //DownloadFile.DownloadFileMethod_2(Context, filePath, 5242880);
              WriteFile(bytes, fileName, filesize, MimeType + " " + extension_Without_dot, context.Response);
        }

       private void WriteFile(byte[] content, string fileName, string filesize, string contentType, HttpResponse response)
    {
        response.Buffer = true;
        response.Clear();

        response.ContentType = contentType;

        response.AddHeader("content-disposition", "attachment; filename=" + fileName);

        response.AddHeader("Content-Length", filesize);

        response.BinaryWrite(content);
        response.Flush();
        response.End();
    }

        private string GetMimeType(string fileName)
        {
            string mimeType = "application/unknown";
            string ext = System.IO.Path.GetExtension(fileName).ToLower();
            Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
            if (regKey != null && regKey.GetValue("Content Type") != null)
                mimeType = regKey.GetValue("Content Type").ToString();
            return mimeType;
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

заранее спасибо

Ответы [ 3 ]

3 голосов
/ 10 ноября 2011

Ни один массив в .NET не может содержать более 2 ^ 31 элемента (System.Int32.MaxValue) или максимальный размер 2 ГБ , что примерно соответствует 2 ГБ байтового массива.

Обходной путь см. http://blogs.msdn.com/b/joshwil/archive/2005/08/10/450202.aspx

Другой вариант - использовать MemoryMappedFile и Streams для тех - это позволит получить доступ к файлу любого размера...

Чтобы этот код загрузки работал, вы можете либо прочитать фрагмент, отправить его, прочитать следующий фрагмент и т. Д. ИЛИ использовать Stream для чтения и записи в OutputStream без промежуточного буфера ...

Другой вариант - использовать TransmitFile, который может обрабатывать файлы размером> 4 ГБ.

EDIT - согласно комментарию:

Вы можете просто заменить код после

if (filePath == null)
{
return;
}

на

response.Clear();

response.ContentType = GetMimeType (System.IO.Path.GetFileName(filePath));

response.AddHeader("content-disposition", "attachment; filename=" + System.IO.Path.GetFileName(filePath));

response.TransmitFile (filePath);    

ИЛИ на

long FileL = (new FileInfo(filePath)).Length;
byte[] bytes = new byte[1024*1024];

response.Clear();

response.ContentType = GetMimeType (System.IO.Path.GetFileName(filePath));

response.AddHeader("content-disposition", "attachment; filename=" + System.IO.Path.GetFileName(filePath));

response.AddHeader("Content-Length", FileL.ToString());

using (FileStream FS = File.OpenRead(filePath))
{
int bytesRead = 0;
while ((bytesRead = FS.Read (bytes, 0, bytes.Length)) > 0 )
{
response.OutputStream.Write(bytes, 0, bytesRead);
response.Flush();
};

response.Close();
}
2 голосов
/ 10 ноября 2011

В .NET самый большой объект, который вы можете выделить, составляет около 2 ГБ.Цитата из документации :

Как и в 32-битных операционных системах Windows, существует ограничение в 2 ГБ на размер объекта, который вы можете создать при запуске 64-битной управляемой системы.приложение в 64-разрядной операционной системе Windows.

Существует также сообщение в блоге от команды CLR.

Конечно, 2 ГБ - теоретический предел.Практический предел ниже.Так что вам придется читать это в виде кусков:

const int ChunkSize = 1024 * 1024 * 4; // process in chunks of 4MB:
using (var br = new BinaryReader(streamReader.BaseStream))
{
    var buffer = new byte[ChunkSize];
    int bytesRead;
    while ((bytesRead = br.Read(buffer, 0, buffer.Length)) > 0)
    {
        // TODO: process the chunk which is the buffer array from 0 to bytesRead
    }
}

Также ваш код кажется немного странным.У вас есть StreamReader, который обрабатывает закодированные строки, и все же вы работаете с байтовыми массивами и BinaryReaders.Кажется странным.

2 голосов
/ 10 ноября 2011

Вам нужно будет использовать меньший буфер и читать поток по частям.Я не думаю, что вы сможете создать байтовый массив размером более 4 ГБ.

Если вы используете .NET 4, вы можете использовать новый экземпляр Stream.CopyTo (Stream)метод для копирования входного потока в выходной поток.

...