如何在没有BinaryReader循环的情况下将二进制文件读取为int[] ?



据我所知,BinaryReader循环性能很差。我能想到的另一种方法是先ReadAllBytes,然后Buffer。BlockCopy到int[]中,但这会导致额外的拷贝。有可能直接将一个巨大的二进制文件高效地读入int[]吗?

你可以使用MemoryMarshal。AsBytes读取所有数据:

using var stream = new FileStream(...);
var target = new int[stream.Length / 4];
stream.Read(MemoryMarshal.AsBytes(target.AsSpan()));

此处不使用BinaryReader。注意int表示的字节顺序。如果文件与您的硬件不匹配,上面的代码可能会导致问题。

如果你想以另一种类型读取数组,你可以使用MemoryMarshal.Cast。

using System;
using System.Runtime.InteropServices;
class Program
{
public static void Main(string[] args)
{
byte[] arrayByte = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };
Span<int> spanInt = MemoryMarshal.Cast<byte, int>(arrayByte);
Console.WriteLine("0x{0:X8}", spanInt[0]); // For little endian it will be 0x44332211.
Console.WriteLine("0x{0:X8}", spanInt[1]); // For little endian it will be 0x88776655.
}
}

另一个选择是Unsafe.As。但是,存在一些问题,例如Length不反映转换后的类型值。我建议使用MemoryMarshal类。

using System;
using System.Runtime.CompilerServices;
class Program
{
public static void Main(string[] args)
{
byte[] arrayByte = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };
int[] arrayInt = Unsafe.As<byte[], int[]>(ref arrayByte);
Console.WriteLine("Length={0}", arrayInt.Length); // 8!? omg...
Console.WriteLine("0x{0:X8}", arrayInt[0]); // For little endian it will be 0x44332211.
Console.WriteLine("0x{0:X8}", arrayInt[1]); // For little endian it will be 0x88776655.
}
}