有效地将int数组写入文件

时间:2019-05-07 19:46:55

标签: c# .net binarywriter

我有一个可能更大的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数组的方法吗?

3 个答案:

答案 0 :(得分:2)

我认为对上述每种方法进行基准测试是很有趣的,@ Jonathan-Wood(TestCopyStream)的原始方法,@ Mike-Zboray(TestCopySpan)的Span建议以及@ oleg-bondarenko的Buffer BlockCopy( TestCopySpanByteCopy)[是的,很难命名]。

我正在生成大小为N的随机数的整数数组,每次运行都具有相同的集合。

结果如下:

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

答案 1 :(得分:1)

.NET Core中没有通过MemoryMarshal.Cast和Span<T>复制的任何内容,都支持最有效的格式。这将直接重新解释内存,但是在跨平台上可能是不可移植的,因此应谨慎使用:

 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都有自己的内部缓冲区,在编写此类int时会使用它们。

答案 2 :(得分:0)

我不确定,但是您可以尝试myIntArray.SelectMany(BitConverter.GetBytes).ToArray()(执行时间4700毫秒)

还有其他方法

var binFormatter = new BinaryFormatter();
var mStream = new MemoryStream();
binFormatter.Serialize(mStream, myIntArray);  

mStream.ToArray(); 

(执行时间2700ms)

这是我发现并通过观察者探查器检查过的最快方法:执行时间1500毫秒(无3d参与者组件),其他方式约为1700毫秒(MemoryMarshal),“对于每个”方法-2700毫秒

            int maxValue = Int32.MaxValue / 50;
            int[] myIntArray = Enumerable.Range(0, maxValue).ToArray();
            var path = "e:\\temp\\1.test";
            using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create)))
            {
                int intLength = myIntArray.Length;
                writer.Write(intLength);

                byte[] bytes = new byte[intLength * sizeof(int)];
                Buffer.BlockCopy(myIntArray, 0, bytes, 0, sizeof(byte));
                writer.Write(bytes);
            }