3

我在内存中有一个非常大的二维字节数组,

byte MyBA = new byte[int.MaxValue][10];

有什么方法(可能不安全)可以让 C# 认为这是一个巨大的连续字节数组?我想这样做,以便我可以将它传递给 aMemoryStream然后 a BinaryReader

MyReader = new BinaryReader(MemoryStream(*MyBA)) //Syntax obviously made-up here
4

6 回答 6

7

我不相信 .NET 提供了这个,但是实现你自己的实现应该相当容易System.IO.Stream,无缝切换支持数组。以下是(未经测试的)基础知识:

public class MultiArrayMemoryStream: System.IO.Stream
{
    byte[][] _arrays;
    long _position;
    int _arrayNumber;
    int _posInArray;

    public MultiArrayMemoryStream(byte[][] arrays){
        _arrays = arrays;
        _position = 0;
        _arrayNumber = 0;
        _posInArray = 0;
    }

    public override int Read(byte[] buffer, int offset, int count){
        int read = 0;
        while(read<count){
            if(_arrayNumber>=_arrays.Length){
                return read;
            }
            if(count-read <= _arrays[_arrayNumber].Length - _posInArray){
                Buffer.BlockCopy(_arrays[_arrayNumber], _posInArray, buffer, offset+read, count-read);
                _posInArray+=count-read;
                            _position+=count-read;
                read=count;
            }else{
                Buffer.BlockCopy(_arrays[_arrayNumber], _posInArray, buffer, offset+read, _arrays[_arrayNumber].Length - _posInArray);
                read+=_arrays[_arrayNumber].Length - _posInArray;
                            _position+=_arrays[_arrayNumber].Length - _posInArray;
                _arrayNumber++;
                _posInArray=0;
            }
        }
        return count;
    }

    public override long Length{
        get {
            long res = 0;
            for(int i=0;i<_arrays.Length;i++){
                res+=_arrays[i].Length;
            }
            return res;
        }
    }

    public override long Position{
        get { return _position; }
        set { throw new NotSupportedException(); }
    }

    public override bool CanRead{
        get { return true; }
    }

    public override bool CanSeek{
        get { return false; }
    }

    public override bool CanWrite{
        get { return false; }
    }

    public override void Flush(){
    }

    public override void Seek(long offset, SeekOrigin origin){
        throw new NotSupportedException();
    }

    public override void SetLength(long value){
        throw new NotSupportedException();
    }

    public override void Write(byte[] buffer, int offset, int count){
        throw new NotSupportedException();
    }       
}

另一种解决 2^31 字节大小限制的方法是在非托管内存缓冲区(可能与操作系统支持的一样大)之上UnmanagedMemoryStream实现。System.IO.Stream像这样的东西可能有效(未经测试):

var fileStream = new FileStream("data", 
  FileMode.Open, 
  FileAccess.Read, 
  FileShare.Read, 
  16 * 1024, 
  FileOptions.SequentialScan);
long length = fileStream.Length;
IntPtr buffer = Marshal.AllocHGlobal(new IntPtr(length));
var memoryStream = new UnmanagedMemoryStream((byte*) buffer.ToPointer(), length, length, FileAccess.ReadWrite);
fileStream.CopyTo(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
// work with the UnmanagedMemoryStream
Marshal.FreeHGlobal(buffer);
于 2010-09-06T12:58:00.537 回答
1

同意。无论如何,你有数组大小本身的限制。

如果您确实需要在流中操作巨大的数组,请编写您的自定义内存流类。

于 2010-09-06T12:57:44.657 回答
0

我认为您可以使用以下方法使用线性结构而不是二维结构。

您可以使用 byte[int.MaxValue*10] 而不是 byte[int.MaxValue][10]。您可以将 [4,5] 处的项目寻址为 int.MaxValue*(4-1)+(5-1)。(一般公式是(i-1)*列数+(j-1)。

当然,您可以使用其他约定。

于 2010-09-06T13:18:37.820 回答
0

如果我正确理解了您的问题,那么您有一个庞大的文件要读入内存然后进行处理。但是你不能这样做,因为文件中的数据量超过了任何一维数组。

您提到速度很重要,并且您有多个并行运行的线程以尽可能快地处理数据。如果您无论如何都必须为每个线程划分数据,为什么不将线程数基于byte[int.MaxValue]覆盖所有内容所需的缓冲区数呢?

于 2010-09-06T13:23:06.703 回答
0

如果您使用的是 Framework 4.0,则可以选择使用MemoryMappedFile。内存映射文件可以由物理文件或 Windows 交换文件支持。内存映射文件就像内存中的流一样,在需要时透明地与后备存储交换数据。

如果您不使用 Framework 4.0,您仍然可以使用此选项,但您需要自己编写或找到现有的包装器。我希望The Code Project上有很多内容。

于 2010-09-06T14:24:10.173 回答
0

您可以创建一个 memoryStream,然后使用方法Write逐行传递数组

编辑: MemoryStream 的限制肯定是您的应用程序存在的内存量。也许有一个限制,但如果您需要更多内存,那么您应该考虑修改您的整体架构。例如,您可以分块处理数据,或者您可以对文件执行交换机制。

于 2010-09-06T12:42:34.117 回答