简体   繁体   English

算术运算导致溢出错误-对于c#中的byte []数组

[英]Arithmetic operation resulted in an overflow ERROR - for byte[] arrays in c#

i have this line in c# : 我在C#中有这行:

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

That Length returns a file size bigger than 4 GB. 该长度返回的文件大小大于4 GB。

at that line i have the Error below : 在那一行我有以下错误:

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

how can i fix this error ? 我该如何解决此错误?

edit 编辑
i am using .net 4 我正在使用.net 4
that code was part of a handler for download files like below : 该代码是用于下载文件的处理程序的一部分,如下所示:

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;
            }
        }
    }
}

thanks in advance 提前致谢

No array in .NET can hold more than 2^31 element ( System.Int32.MaxValue ) or a max size of 2 GB which roughly would make for a 2 GB byte array. .NET中的任何数组都不能容纳超过2 ^ 31个元素( System.Int32.MaxValue )或2 GB的最大大小,这大约可以构成2 GB的字节数组。

For a workaround see http://blogs.msdn.com/b/joshwil/archive/2005/08/10/450202.aspx 有关解决方法,请参见http://blogs.msdn.com/b/joshwil/archive/2005/08/10/450202.aspx

Another option is to use MemoryMappedFile and Streams on those - this will alow to access a file of any size... 另一个选择是在这些文件上使用MemoryMappedFileStreams-这将允许访问任何大小的文件...

To make that download code work you could either read a chunk, send it, read the next chunk etc. OR use a Stream for reading and write to the OutputStream without any intermediate buffer... 为了让这个下载代码的工作,你既可以读一大块,发送,阅读下一大块等,或使用Stream读取和写入OutputStream没有任何中间缓冲...

Another option is to use TransmitFile which can handle files > 4 GB. 另一种选择是使用TransmitFile ,它可以处理大于4 GB的文件。

EDIT - as per comment: 编辑-根据评论:

You could just replace the code after 您可以在之后替换代码

if (filePath == null)
{
return;
}

with

response.Clear();

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

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

response.TransmitFile (filePath);    

OR with

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();
}

You're going to have to use a smaller buffer and read the stream piecemeal. 您将不得不使用较小的缓冲区并逐个读取流。 I don't think you're going to be able to create a byte array that's bigger than 4 GB. 我认为您将无法创建大于4 GB的字节数组。

If you're using .NET 4, you can use the new Stream.CopyTo(Stream) instance method to copy the input stream to an output stream. 如果使用的是.NET 4,则可以使用新的Stream.CopyTo(Stream)实例方法将输入流复制到输出流。

In .NET the largest object you could allocate is around 2GB. 在.NET中,您可以分配的最大对象约为2GB。 Quote from the documentation : 文档引用:

As with 32-bit Windows operating systems, there is a 2GB limit on the size of an object you can create while running a 64-bit managed application on a 64-bit Windows operating system. 与32位Windows操作系统一样,在64位Windows操作系统上运行64位托管应用程序时,可以创建的对象大小限制为2GB。

There is also a blog post from the CLR team. 还有CLR团队的博客文章

Of course 2GB is the theoretical limit. 当然2GB是理论上的限制。 The practical limit is lower. 实际极限较低。 So you will have to read this in chunks: 因此,您将必须阅读以下内容:

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
    }
}

Also your code seems a bit strange. 而且您的代码似乎有点奇怪。 You have a StreamReader which processes encoded strings and yet you are working with byte arrays and BinaryReaders. 您有一个StreamReader,它处理编码的字符串,但是您正在使用字节数组和BinaryReaders。 Seems kinda strange. 似乎有点奇怪。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM