Быстрое чтение массива структур из бинарного файла

Можно ли за один вызов прочитать массив структур из бинарного файла?

Например, у меня есть файл, содержащий тысячи вершин:

struct Vector3 { float x, y, z; }

Мне нужен порт С# для кода С++:

Vector3 *verts = new Vector3[num_verts];
fread ( verts, sizeof(Vector3), num_verts, f );

person Newbee    schedule 11.01.2013    source источник


Ответы (2)


Вот один (из нескольких) способов:

void Main()
{
    var pts = 
        (from x in Enumerable.Range(0, 10)
        from y in Enumerable.Range(0, 10)
        from z in Enumerable.Range(0, 10)
        select new Vector3(){X = x, Y = y, Z = z}).ToArray();

    // write it out...
    var bigAssByteArray = new byte[Marshal.SizeOf(typeof(Vector3)) * pts.Length];
    var pinnedHandle = GCHandle.Alloc(pts, GCHandleType.Pinned);    
    Marshal.Copy(pinnedHandle.AddrOfPinnedObject(), bigAssByteArray, 0, bigAssByteArray.Length);
    pinnedHandle.Free();
    File.WriteAllBytes(@"c:\temp\vectors.out", bigAssByteArray);

    // ok, read it back...
    var readBytes = File.ReadAllBytes(@"c:\temp\vectors.out");
    var numVectors = readBytes.Length / Marshal.SizeOf(typeof(Vector3));
    var readVectors = new Vector3[numVectors];
    pinnedHandle = GCHandle.Alloc(readVectors, GCHandleType.Pinned);
    Marshal.Copy(readBytes, 0, pinnedHandle.AddrOfPinnedObject(), readBytes.Length);
    pinnedHandle.Free();

    var allEqual = 
        pts.Zip(readVectors, 
            (v1,v2) => (v1.X == v2.X) && (v1.Y == v2.Y) && (v1.Z == v2.Z))
        .All(p => p);
    Console.WriteLine("pts == readVectors? {0}", allEqual);
}


struct Vector3
{
    public float X;
    public float Y;
    public float Z;
}
person JerKimball    schedule 11.01.2013

Да, это возможно, но вам придется добавить атрибуты в структуру, чтобы точно указать, как она отображается в памяти, чтобы в структуре не было заполнения.

Часто проще просто преобразовать данные самостоятельно. Подавляющее большинство времени обработки будет занимать чтение данных из файла, поэтому накладные расходы на преобразование данных невелики. Пример:

byte[] bytes = File.ReadAllBytes(fileName);
Vector3[] data = new Vector3[bytes.Length / 12];
for (var i = 0; i < data.Length; i++) {
  Vector3 item;
  item.x = BitConverter.ToSingle(bytes, i * 12);
  item.y = BitConverter.ToSingle(bytes, i * 12 + 4);
  item.z = BitConverter.ToSingle(bytes, i * 12 + 8);
  data[i] = item;
}
person Guffa    schedule 11.01.2013
comment
В целом верно, хотя упорядоченный размер поплавка равен 4, поэтому вам не нужно беспокоиться об изменении размера пакета. - person JerKimball; 11.01.2013