高效地将 int 数组写入文件

Efficiently writing an int array to file

我有一个可能更大的 int 数组,我正在使用 BinaryWriter 写入文件。当然,我可以使用默认的方式。

using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create)))
{
    writer.Write(myIntArray.Length);
    foreach (int value in myIntArray)
        writer.Write(value);
}

但这似乎非常低效。我很确定 int 数组在内存中连续存储数据。有没有办法像使用 byte 数组那样将内存直接写入文件?也许是一种将 int 数组转换(而不是复制)到 byte 数组的方法?

通过 MemoryMarshal.Cast 和 Span<T> 支持最有效的形式,无需在 .NET Core 中进行任何复制。这直接重新解释了内存,但这可能无法跨平台移植,因此应谨慎使用:

 int[] values = { 1, 2, 3 };

 using (var writer = new BinaryWriter(File.Open(path, FileMode.Create)))
 {
     Span<byte> bytes = MemoryMarshal.Cast<int, byte>(values.AsSpan());
     writer.Write(bytes);
 }

此 API 从 MemoryExtensions.NonPortableCast

移动时的一些相关讨论

但是我会说你的原版实际上会相当有效,因为 BinaryWriter 和 FileStream 都有自己的内部缓冲区,在编写这样的整数时会使用这些缓冲区。

我认为对上面列出的每个方法进行基准测试会很有趣,原始方法来自@Jonathan-Wood (TestCopyStream),来自@Mike-Zboray (TestCopySpan) 的 Span 建议和 Buffer BlockCopy来自@oleg-bondarenko (TestCopySpanByteCopy) [是的,命名很难]。

我正在生成大小为 N 的随机数 int 数组,每个 运行 的集合相同。

结果如下:

|               Method |     N |     Mean |     Error |    StdDev |   Median | Ratio | RatioSD | Rank |   Gen 0 | Gen 1 | Gen 2 | Allocated |
|--------------------- |------ |---------:|----------:|----------:|---------:|------:|--------:|-----:|--------:|------:|------:|----------:|
|         TestCopySpan |  1000 | 1.372 ms | 0.0382 ms | 0.1109 ms | 1.348 ms |  1.00 |    0.11 |    1 |       - |     - |     - |    4984 B |
|       TestCopyStream |  1000 | 1.377 ms | 0.0324 ms | 0.0935 ms | 1.364 ms |  1.00 |    0.00 |    1 |       - |     - |     - |    4984 B |
| TestCopySpanByteCopy |  1000 | 2.215 ms | 0.0700 ms | 0.2008 ms | 2.111 ms |  1.62 |    0.19 |    2 |  3.9063 |     - |     - |   13424 B |
|                      |       |          |           |           |          |       |         |      |         |       |       |           |
|         TestCopySpan | 10000 | 1.617 ms | 0.1167 ms | 0.3155 ms | 1.547 ms |  0.80 |    0.19 |    1 |       - |     - |     - |     864 B |
|       TestCopyStream | 10000 | 2.032 ms | 0.0776 ms | 0.2251 ms | 1.967 ms |  1.00 |    0.00 |    2 |       - |     - |     - |    4984 B |
| TestCopySpanByteCopy | 10000 | 2.433 ms | 0.0703 ms | 0.2040 ms | 2.430 ms |  1.21 |    0.18 |    3 | 11.7188 |     - |     - |   45304 B |