我在内存中有一个非常大的2D字节数组,
byte MyBA = new byte[int.MaxValue][10];
有什么方法(可能不安全)我可以欺骗C#认为这是一个巨大的连续字节数组?我想这样做,以便我可以将其传递给MemoryStream
,然后传递给BinaryReader
。
MyReader = new BinaryReader(MemoryStream(*MyBA)) //Syntax obviously made-up here
答案 0 :(得分: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);
答案 1 :(得分:1)
同意。无论如何,你有自己的数组大小限制。
如果您确实需要在流中操作大型数组,请编写自定义内存流类。
答案 2 :(得分:0)
您可以创建一个memoryStream,然后使用Write方法逐行传递数组
编辑: MemoryStream的限制当然是应用程序的内存量。也许有一个限制,但如果你需要更多的内存,那么你应该考虑修改你的整体架构。例如。您可以以块的形式处理数据,也可以对文件执行交换机制。
答案 3 :(得分:0)
我认为您可以使用以下方法使用线性结构而不是2D结构。
您可以使用byte [int.MaxValue * 10]而不是byte [int.MaxValue] [10]。您可以将[4,5]处的项目称为int.MaxValue *(4-1)+(5-1)。 (通式为(i-1)*列数+(j-1)。
当然你可以使用其他约定。
答案 4 :(得分:0)
如果我正确理解了你的问题,你就会有一个大量的文件,你想要读入内存然后处理。但是你不能这样做,因为文件中的数据量超过了任何一维数组的数据。
您提到速度很重要,并且您有多个并行运行的线程可以尽快处理数据。如果您不得不为每个线程分配数据,为什么不将线程数基于覆盖所有内容所需的byte[int.MaxValue]
缓冲区数量?
答案 5 :(得分:0)
如果您使用的是Framework 4.0,则可以选择使用MemoryMappedFile。内存映射文件可以由物理文件或Windows交换文件支持。内存映射文件就像内存中的流一样,在需要时透明地与后备存储交换数据。
如果您没有使用Framework 4.0,您仍然可以使用此选项,但您需要自己编写或找到一个现有的包装器。我希望The Code Project上有很多。