Можно ли в качестве двумерного байтового массива сделать один огромный непрерывный байтовый массив? - PullRequest
3 голосов
/ 06 сентября 2010

У меня очень большой 2D-байт в памяти,

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

Есть ли способ (возможно, небезопасный), что я могу обмануть C #, думая, что это один огромный непрерывный байтовый массив? Я хочу сделать это так, чтобы я мог передать его MemoryStream, а затем BinaryReader.

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

Ответы [ 6 ]

7 голосов
/ 06 сентября 2010

Я не верю, что .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 голос
/ 06 сентября 2010

Согласен. В любом случае у вас есть предел размера самого массива.

Если вам действительно нужно работать с огромными массивами в потоке, напишите свой собственный класс потока памяти.

0 голосов
/ 06 сентября 2010

Если вы используете Framework 4.0, у вас есть возможность работать с MemoryMappedFile .Файлы, отображаемые в память, могут быть сохранены в виде физического файла или файла подкачки Windows.Файлы с отображением в памяти действуют как поток в памяти, прозрачно обменивая данные в / из резервного хранилища, если и когда это необходимо.

Если вы не используете Framework 4.0, вы все равно можете использовать эту опцию, но вам потребуетсялибо написать свой собственный, либо найти интересующую обертку.Я ожидаю, что есть много на The Code Project .

0 голосов
/ 06 сентября 2010

Если я правильно понимаю ваш вопрос, у вас есть массивный файл, который вы хотите прочитать в память, а затем обработать. Но вы не можете сделать это, потому что объем данных в файле превышает объем любого одномерного массива.

Вы упомянули, что скорость важна, и что у вас есть несколько потоков, работающих параллельно для максимально быстрой обработки данных. Если вам все равно придется разделять данные для каждого потока, почему бы не основать количество потоков на количестве byte[int.MaxValue] буферов, необходимых для всего?

0 голосов
/ 06 сентября 2010

Я думаю, что вы можете использовать линейную структуру вместо 2D, используя следующий подход.

Вместо байта [int.MaxValue] [10] вы можете иметь байт [int.MaxValue * 10]. Вы можете обратиться к пункту в [4,5] как int.MaxValue * (4-1) + (5-1). (общая формула будет (i-1) * количество столбцов + (j-1).

Конечно, вы можете использовать другое соглашение.

0 голосов
/ 06 сентября 2010

Вы можете создать memoryStream, а затем передать массив построчно, используя метод Запись

РЕДАКТИРОВАТЬ: предел MemoryStream, безусловно, представляет собой объем памяти, представленной для вашего приложения,Может быть, есть ограничение под этим, но если вам нужно больше памяти, то вы должны изменить общую архитектуру.Например, вы можете обрабатывать ваши данные порциями, или вы можете использовать механизм обмена файлами.

...