投稿者 魔界の仮面弁士  (社会人) 投稿日時 2022/10/20 21:35:17
先の回答で「案1」と「案2」を設けましたが、手順的にはこのようなものです。

【案1】
 ファイル全体を一括で読み取った後で、そのバイナリをループ処理で
 切り出して構造体に変換していく手法。

① byte[] に全データを一括して取り込む。(バッファーサイズ = すべてのレコードの総量)
 最初の投稿にあった FileStream.Read でも良いですが、File.ReadAllBytes の方が処理としては楽かと。
 もしも FileStream.Read を使うなら、現状のように Marshal 処理の最中まで開き続けるのではなく
 全件 Read した時点で、ストリームを即時に閉じるべきです。

② byte[] の読み込み位置をずらしながら、1 レコードずつ Copy していきます。
 KOZ さんが書かれているように、読み込み開始位置は Marshal.Copy の第二引数で指定します。


byte[] buf = File.ReadAllBytes(filePath);           // ファイル全体を一括読み込みしてすぐにファイルを閉じる
int fileSize = buf.Length;                          // ファイルサイズ
int structSize = Marshal.SizeOf<Form1.usrData>();   // 構造体サイズ

IntPtr ptr = Marshal.AllocCoTaskMem(structSize);    // 単一レコード分のメモリを確保

Form1.usrData[] dataArray = new Form1.usrData[fileSize / structSize];  // 総レコード数を求めて配列を準備
for (int n = 0; n < dataArray.Length; n++)
{
    Marshal.Copy(buf, n * structSize, ptr, structSize);  // バッファ内のbuf[n]~buf[n+structSize-1] の範囲を転写
    dataArray[n] = Marshal.PtrToStructure<Form1.usrData>(ptr);  // 構造体として取得して順次配列に入れていく
}
Marshal.FreeHGlobal(ptr);   // メモリ解放

表示処理(dataArray);




【案2の場合】
 構造体と同じ大きさのメモリサイズを 1 ブロックとして、少しずつ読み取っていく手法。
 分割して読み取った分を順次、構造体に変換する処理を繰り返し行う。

① byte[] として確保するバッファーサイズは、ファイルサイズと同等では無く、
 構造体の 1 レコードと同等サイズとします。
 1 レコード分だけ Read しては Copy、また Read しては Copy を繰り返すようにする流れです。

② byte[] には現在の 1 レコード分しか無いので、この手法では
 Marshal.Copy の第二引数は常に 0 固定となります。


var dataList = new List<Form1.usrData>();
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
    int structSize = Marshal.SizeOf<Form1.usrData>();   // 構造体サイズ
    IntPtr ptr = Marshal.AllocCoTaskMem(structSize);    // 単一レコード分のメモリを確保
    byte[] buf = new byte[structSize];  // ファイル全体ではなく 1 レコード分だけのバッファ
    while (fs.Read(buf, 0, structSize) == structSize)   // バッファの buf[0]~buf[structSize-1] の位置に次のレコードを読み取る
    {
        Marshal.Copy(buf, 0, ptr, structSize);  // バッファ内のbuf[0]~buf[structSize-1] の範囲を転写
        dataList.Add(Marshal.PtrToStructure<Form1.usrData>(ptr));  // 構造体として取得して順次 List<> に入れていく
    }
    Marshal.FreeCoTaskMem(ptr);  // メモリ開放
}

表示処理(dataList);