Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to write a short[] array to a file in C#?

I have an array of shorts (short[]) that I need to write out to a file. What's the quickest way to do this?

like image 378
MusiGenesis Avatar asked Oct 22 '08 02:10

MusiGenesis


3 Answers

Use the BinaryWriter

    static void WriteShorts(short[] values, string path)
    {
        using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
        {
            using (BinaryWriter bw = new BinaryWriter(fs))
            {
                foreach (short value in values)
                {
                    bw.Write(value);
                }
            }
        }
    }
like image 181
Jon B Avatar answered Oct 16 '22 06:10

Jon B


Following up on Jon B's answer, if your file contains any other data, you might want to prefix the data with the count of values.

i.e.:

static void WriteShorts(short[] values, string path)
{
    using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
    {
        using (BinaryWriter bw = new BinaryWriter(fs))
        {
            // Write the number of items
            bw.Write(values.Length);

            foreach (short value in values)
            {
                bw.Write(value);
            }
        }
    }
}
like image 2
Brannon Avatar answered Oct 16 '22 08:10

Brannon


BinaryFormatter is in fact about 10 times faster both for reads and writes when used with arrays of primitive types (obj.GetType().IsPrimitive), i.e. not for Decimal and String (which are not primitive) and certainly not for any other struct or class where it instead is horribly slow.

[Test]
public void TestShortArray()
{
  var n = 100000000;
  var input = new short[n];
  var r = new Random();
  for (var i = 0; i < n; i++) input[i] = (short)r.Next();
  var bf = new BinaryFormatter();
  var sw = new Stopwatch();
  using (var ms = new MemoryStream())
  {
    sw.Start();
    bf.Serialize(ms, input);
    sw.Stop();
    Console.WriteLine("BinaryFormatter serialize: " +
      sw.ElapsedMilliseconds + " ms, " + ms.ToArray().Length + " bytes");
    sw.Reset();
    ms.Seek(0, SeekOrigin.Begin);
    sw.Start();
    var output = (short[])bf.Deserialize(ms);
    sw.Stop();
    Console.WriteLine("BinaryFormatter deserialize: " +
      sw.ElapsedMilliseconds + " ms, " + ms.ToArray().Length + " bytes");
    Assert.AreEqual(input, output);
  }
  sw.Reset();
  using (var ms = new MemoryStream())
  {
    var bw = new BinaryWriter(ms, Encoding.UTF8, true);
    sw.Start();
    bw.Write(input.Length);
    for (var i = 0; i < input.Length; i++) bw.Write(input[i]);
    sw.Stop();
    Console.WriteLine("BinaryWriter serialize: " +
      sw.ElapsedMilliseconds + " ms, " + ms.ToArray().Length + " bytes");
    sw.Reset();
    ms.Seek(0, SeekOrigin.Begin);
    var br = new BinaryReader(ms, Encoding.UTF8, true);
    sw.Start();
    var length = br.ReadInt32();
    var output = new short[length];
    for (var i = 0; i < length; i++) output[i] = br.ReadInt16();
    sw.Stop();
    Console.WriteLine("BinaryReader deserialize: " +
      sw.ElapsedMilliseconds + " ms, " + ms.ToArray().Length + " bytes");
    Assert.AreEqual(input, output);
  }
}

Output:

BinaryFormatter serialize: 175 ms, 200000028 bytes
BinaryFormatter deserialize: 79 ms, 200000028 bytes
BinaryWriter serialize: 1499 ms, 200000004 bytes
BinaryReader deserialize: 1599 ms, 200000004 bytes

So use BinaryFormatter whenever you have an array of a primitive type, or array of arrays but not multi-dim arrays (!). If your datatype is for instance Point3(double) you should fill up a double[] and serialize that instead. Only use BinaryWriter for complex/mixed types, strings, decimals and singular values.

When dealing with byte[] then BinaryFormatter and BinaryWriter is equally performant (and very fast). If you can convert your type to byte-array in an effective way you may get even faster performance this way.

like image 1
Andreas Zita Avatar answered Oct 16 '22 07:10

Andreas Zita