Я не верю, что .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
поверх буфера неуправляемых памятей (который может быть столь же большим, как опоры OS). Что-то вроде этого может работать (непроверено):
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);
Предполагая, что int 32 бита, по 10 каждый, не делает ваш массив 40 гигабайтами? –
Я понимаю вашу проблему, но почему вы пытаетесь выделить такой большой массив? Я не сомневаюсь, что даже если вам удастся решить эту техническую проблему, ваша архитектура ошибочна, и программа, которую вы пытаетесь разработать, в конечном итоге не будет работать. – Gilad
Gilad, мне нужно выделить большой массив, чтобы иметь возможность обрабатывать его в памяти. Для меня очень важна скорость. Кроме того, у меня много потоков, обрабатывающих одни и те же данные одновременно. Я понимаю вашу озабоченность, но в этой области уже работают данные с точностью до граничного предела, который является максимальным размером байтаря. Если бы я мог удалить этот предел (или дурак C#), то я не вижу причин, по которым он не должен продолжать работать. – ManInMoon