Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficiently writing an int array to file

I have a potentially larger int array that I'm writing to a file using BinaryWriter. Of course, I can use the default approach.

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

But this seems horribly inefficient. I'm pretty sure an int array stores data contiguously in memory. Is there no way to just write the memory directly to a file like you can with a byte array? Maybe a way to cast (not copy) the int array to a byte array?

like image 492
Jonathan Wood Avatar asked May 15 '26 16:05

Jonathan Wood


2 Answers

There is support for the most efficient form without any copying in .NET Core via MemoryMarshal.Cast and Span<T>. This directly reinterprets the memory but this is potentially nonportable across platforms so it should be used with care:

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

Some relevant discussion of this API when it was moved from MemoryExtensions.NonPortableCast

However I will say your original is actually going to be fairly efficient because both BinaryWriter and FileStream have their own internal buffers that are used when writing ints like that.

like image 80
Mike Zboray Avatar answered May 17 '26 05:05

Mike Zboray


I thought it would be interesting to benchmark each of the methods outlined above, the original from @Jonathan-Wood (TestCopyStream), the Span suggestion from @Mike-Zboray (TestCopySpan) and the Buffer BlockCopy from @oleg-bondarenko (TestCopySpanByteCopy) [yup, naming things is hard].

I'm generating int arrays of size N of random numbers, the same set for each run.

Here's the results:

|               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 |
like image 27
penderi Avatar answered May 17 '26 04:05

penderi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!