Pregunta

Is it possible to read an array of structs from binary file in one call?

For example, I have a file containing thousands of vertices:

struct Vector3 { float x, y, z; }

I need C# port for the C++ code:

Vector3 *verts = new Vector3[num_verts];
fread ( verts, sizeof(Vector3), num_verts, f );
¿Fue útil?

Solución

Here's one (of a few) ways:

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;
}

Otros consejos

Yes, it's possible, but you would have to add attributes to the structure so that you specify exactly how it's mapped in memory so that there is no padding in the struct.

Often it's easier to just convert the data yourself. The vast majority of the processing time will be reading the data from the file, so the overhead of converting the data is small. Example:

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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top