1回の呼び出しでバイナリファイルから構造体の配列を読み取ることは可能ですか?
たとえば、何千もの頂点を含むファイルがあります。
struct Vector3 { float x, y, z; }
C++ コード用の C# ポートが必要です。
Vector3 *verts = new Vector3[num_verts];
fread ( verts, sizeof(Vector3), num_verts, f );
1回の呼び出しでバイナリファイルから構造体の配列を読み取ることは可能ですか?
たとえば、何千もの頂点を含むファイルがあります。
struct Vector3 { float x, y, z; }
C++ コード用の C# ポートが必要です。
Vector3 *verts = new Vector3[num_verts];
fread ( verts, sizeof(Vector3), num_verts, f );
(いくつかの) 方法の 1 つを次に示します。
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;
}
はい、可能ですが、構造体にパディングがないように、メモリ内でのマッピング方法を正確に指定するために、構造体に属性を追加する必要があります。
多くの場合、自分でデータを変換する方が簡単です。処理時間の大部分はファイルからのデータの読み取りに費やされるため、データ変換のオーバーヘッドはわずかです。例:
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;
}