3

メモリ内に非常に大きな 2D バイト配列があり、

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

これが 1 つの巨大な連続したバイト配列であると C# をだますことができる (おそらく安全ではない) 方法はありますか? MemoryStreamこれを a に渡してから aに渡すことができるようにしたいBinaryReader

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

6 に答える 6

7

System.IO.Stream.NET がこれを提供しているとは思いませんが、バッキング アレイをシームレスに切り替えるの独自の実装を実装するのはかなり簡単なはずです。(テストされていない)基本は次のとおりです。

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 バイトのサイズ制限を回避するもう 1 つの方法は、アンマネージ メモリ バッファ (OS がサポートする最大サイズ) の上に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

メソッドWriteを使用して、memoryStream を作成し、配列を 1 行ずつ渡すことができます。

編集: MemoryStream の制限は、確かにアプリケーションに存在するメモリの量です。その下に制限があるかもしれませんが、より多くのメモリが必要な場合は、アーキテクチャ全体を変更することを検討する必要があります。たとえば、データをチャンクで処理したり、ファイルにスワッピング メカニズムを実行したりできます。

于 2010-09-06T12:42:34.117 に答える
0

次のアプローチを使用して、2D 構造の代わりに線形構造を使用できると思います。

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

あなたの質問を正しく理解できれば、大量のファイルをメモリに読み込んで処理したことになります。しかし、ファイル内のデータ量が 1 次元配列のデータ量を超えているため、これを行うことはできません。

速度が重要であり、データをできるだけ速く処理するために複数のスレッドを並行して実行していると述べました。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 に答える