C#. The BinaryWriter class. Working with binary files




The BinaryWriter class. Working with binary files

It is recommended that you familiarize yourself with the following topics before exploring this topic:


Contents


Search other websites:

1. The BinaryWriter class. The purpose

The BinaryWriter class is designed to write data in binary format. Data can be written to files, network, isolated storage, memory, etc. When writing strings, it is possible to specify the desired encoding. The default is UTF-8 encoding.

The class is implemented in the System.IO namespace. In order to use the capabilities of this class, you need to add the line

using System.IO;

The BinaryWriter class writes data that is represented by:

  • primitive types: int, float, double and others;
  • strings of type string in the specified encoding.

 

2. Interaction of the BinaryWriter class with base store streams

The BinaryWriter class (as well as the BinaryReader) is stream adapter. This means the following. To access a file, network, or memory, you need to use an intermediate base store class (FileStream, MemoryStream, NetworkStream, etc.).

The figure shows the interaction of the BinaryWriter class with the file storage, which corresponds to the FileStream class.

C#. The interaction of the BinaryWriter class with the file through the FileStream class

Figure. The interaction of the BinaryWriter class with the file through the FileStream class

 

3. The BinaryWriter class constructors. Creating an instance

The BinaryWriter class has several constructors, the most common of which are:

public BinaryWriter(Stream output)
public BinaryWriter(Stream output, System.Text.Encoding encoding)

here

  • output – a reference to the abstract Stream class, which is the top of the I/O class hierarchy;
  • encoding – encoding system (Unicode, UTF32, UTF8 or other). The default encoding system is UTF8.

Example. In order to create an instance of the BinaryWriter class and associate it with the file “abc.bin”, you need to run the following code.

// Create a file named "abc.bin" for writing
using (FileStream fs = new FileStream("abc.bin", FileMode.Create, FileAccess.Write))
{
  // 2. Link fs stream to bw instance:
  // bw -> fs -> "abc.bin"
  using (BinaryWriter bw = new BinaryWriter(fs, Encoding.Default))
  {

    ...
  }

  ...
}

As you can see from the example, when creating streams the using() keyword is used. This removes the need to close threads using the Close() method, since this approach automatically cleans up resources.

 

4. Basic methods of BinaryWriter class
4.1. The Write() method – many overloaded implementations

The main method of the BinaryWriter class is the Write() method. This method allows you to write data of all primitive (standard) types to the stream.
The method has 20 overloaded implementations, the main of which are listed below.

4.1.1. Writing single values. The overloaded Write() method. Example

To write single values, the Write() methods are used, which have the following general form

public virtual void Write(bool value)
public virtual void Write(byte value)
public virtual void Write(char ch)
public virtual void Write(decimal value)
public virtual void Write(double value)
public virtual void Write(float value)
public virtual void Write(int value)
public virtual void Write(long value)
public virtual void Write(sbyte value)
public virtual void Write(short value)
public virtual void Write(string value)
public virtual void Write(uint value)
public virtual void Write(ulong value)
public virtual void Write(ushort value)

here value is the value of one of the standard (primitive) types to be written to the stream.

Example. In the example, data of different types is written to the file “data.bin” using the Write() method. This data is then read for monitoring purposes.

using System;
using System.IO;
using System.Text;

namespace ConsoleApp10
{
  class Program
  {
    static void Main(string[] args)
    {
      // 1. Write data of different types to the file "data.bin"
      using (FileStream fs = new FileStream("data.bin", FileMode.Create))
      {
        using (BinaryWriter bw = new BinaryWriter(fs, Encoding.Default))
        {
          // Writing data of different types to the "data.bin" file
          bool b = false; // тип bool
          int i = 233;
          double x = 2.338;
          decimal d = 0.011199m;
          float f = -30.88f;

          // Writing
          bw.Write(b); // write the bool type
          bw.Write(i); // write the int type
          bw.Write(x);
          bw.Write(d);
          bw.Write(f);
          bw.Write(1234567890123L); // write the long number
        }
      }

      // 2. Reading data of different types from the "data.bin" file
      using (FileStream fs = new FileStream("data.bin", FileMode.Open))
      {
        using (BinaryReader br = new BinaryReader(fs, Encoding.Default))
        {
          // Reading data of different types
          bool b2 = br.ReadBoolean(); // read the bool type
          int i2 = br.ReadInt32();
          double x2 = br.ReadDouble();
          decimal d2 = br.ReadDecimal();
          float f2 = br.ReadSingle();
          long l2 = br.ReadInt64();

          // Display the read data on the screen for control
          Console.WriteLine("b2 = {0}", b2);
          Console.WriteLine("i2 = {0}", i2);
          Console.WriteLine("x2 = {0:f3}", x2); // precision 3 decimal places
          Console.WriteLine("d2 = {0}", d2);
          Console.WriteLine("f2 = {0:f2}", f2);
          Console.WriteLine($"l2 = {l2}"); // another way to display
        }
      }
    }
  }
}

The result of the program

b2 = False
i2 = 233
x2 = 2.338
d2 = 0.011199
f2 = -30.88
l2 = 1234567890123

 

4.1.2. Writing byte arrays byte[] to the stream. Example

Writing bytes of arrays of type byte[] is useful when arrays of standard types (for example, arrays int[], double[], decimal[], etc.) need to be written to the stream. To convert from standard types to the byte[] type, it is convenient to use the capabilities of the BitConverter class.

public virtual void Write(byte[] buffer)
public virtual void Write(byte[] buffer, int index, int count)

here

  • buffer – memory portion from which data will be written to the stream byte by byte;
  • index – the position (index) of the beginning in the buffer array, from which the stream will be written;
  • count – the number of bytes to be written to the stream.

Example. In the example, using the Write() method, an array of numbers of type double[] is written to the file “array.dat”. Then this array is read and displayed for verification.

using System;
using System.IO;
using System.Text;

namespace ConsoleApp10
{
  class Program
  {
    static void Main(string[] args)
    {
      // Write an array of numbers of type double[] to the file "array.bin"
      // 1. The source array
      double[] AD = { 2.88, 3.11, 4.88 };

      // 2. Writing the array
      using (FileStream fs = new FileStream("array.bin", FileMode.Create))
      {
        using (BinaryWriter bw = new BinaryWriter(fs, Encoding.Default))
        {
          // Additional array of byte[] type
          byte[] AB;

          // First write the number of numbers in AD array
          bw.Write(AD.Length);

          // Loop for writing numbers of decimal[] type
          for (int i=0; i<AD.Length; i++)
          {
            // converting byte[] <- double
            AB = BitConverter.GetBytes(AD[i]);

            // Write double as array of byte[]
            bw.Write(AB, 0, AB.Length);

            // you can do that too
            //bw.Write(AB);
          }
        }
      }

      // 3. Read data from file array.bin"
      using (FileStream fs = new FileStream("array.bin", FileMode.Open))
      {
        using (BinaryReader br = new BinaryReader(fs, Encoding.Default))
        {
          // Declare additional variables
          double[] AD2; // The resulting array

          // additional array buffer
          byte[] B2 = new byte[sizeof(double)]; // allocate memory for B2

          // Count the number of numbers first
          int count = br.ReadInt32();

          // Allocate memory for array AD2
          AD2 = new double[count];

          // Read data from file as byte[] and convert it to double
          for (int i = 0; i < AD2.Length; i++)
          {
            // Read data into buffer as byte[]
            br.Read(B2);

            // convert byte[] -> double
            AD2[i] = BitConverter.ToDouble(B2);
          }

          // Display AD2 for control
          Console.Write("AD2 = { ");
          foreach (double x in AD2)
            Console.Write($"{x} ");
          Console.WriteLine(" }");
        }
      }
    }
  }
}

The result of the program

AD2 = { 2.88 3.11 4.88 }

 

4.1.3. Writing character arrays char[] to a stream. Example

To write character strings as an array char[], the following two implementations of the Write() method are used:

public virtual void Write(char[] chars)
public virtual void Write(char[] chars, int index, int count)

here

  • chars – an array of characters to be written to the stream;
  • index – the position of the first character in the chars array, starting from which you want to write data;
  • count – the number of characters to read from the chars array and write to the stream.

Example. The example writes a string of type string to the file stream as a character array char[].

using System;
using System.IO;
using System.Text;

namespace ConsoleApp10
{
  class Program
  {
    static void Main(string[] args)
    {
      // Write a string as an array char[] to the file "string.bin"
      // 1. The source string
      string s = "bestprog.net";

      // 2. Write the string
      using (FileStream fs = new FileStream("string.bin", FileMode.Create))
      {
        using (BinaryWriter bw = new BinaryWriter(fs, Encoding.Default))
        {
          // Additional array of char[] type
          char[] chars;

          // Converting string -> char[]
          chars = s.ToCharArray();

          // Write the number of characters in the array chars
          bw.Write(chars.Length);

          // Write array chars to the file
          bw.Write(chars);
        }
      }

      // 3. Reading data from file "string.bin"
      using (FileStream fs = new FileStream("string.bin", FileMode.Open))
      {
        using (BinaryReader br = new BinaryReader(fs, Encoding.Default))
        {
          // Declare additional variables
          string s2; // the resulting string

          // additional array-buffer
          char[] chars2;

          // Read the number of elements in file
          int count = br.ReadInt32();

          // Read a string as an array of type char[]
          chars2 = br.ReadChars(count);

          // Convert string chars2 to string
          s2 = new string(chars2);

          // Print s2
          Console.WriteLine(s2); // bestprog.net
        }
      }
    }
  }
}

The result of the program

bestprog.net

 

4.2. The Seek() method. Example

The Seek() method sets the position in the current thread. The general form of the method is as follows:

public virtual long Seek(int offset, System.IO.SeekOrigin origin)

here

  • offset – offset in bytes from the origin position;
  • origin – a value indicating the starting point from which the new position should be obtained.

The value of origin is an enumeration and has the type

enum System.IO.SeekOrigin

Values from the enumeration can be as follows:

  • SeekOrigin.Begin – the starting point of reference is set at the beginning of the stream (file);
  • SeekOrigin.End – the starting point is set at the end of the stream (file);
  • SeekOrigin.Current – the current position in the stream (file) is determined.

Example. The example demonstrates the following operations:

  • write numbers to the file;
  • overwriting previously recorded numbers;
  • appending a number to the end of the file.

 

using System;
using System.IO;
using System.Text;

namespace ConsoleApp10
{
  class Program
  {
    static void Main(string[] args)
    {
      // Writing numbers to the "data.bin" file and replacing them
      // Create a stream associated with the data.bin file: fs -> data.bin
      FileStream fw = new FileStream("data.bin", FileMode.Create);

      // Create the stream adapter bw: bw -> fs -> data.bin
      BinaryWriter bw = new BinaryWriter(fw, Encoding.Default);

      // Write the number of type int
      bw.Write(255);

      // Write the number of type double
      bw.Write(7.88);

      // Overwrite the second double with another value.
      bw.Seek(sizeof(int), SeekOrigin.Begin); // offset - size of int type
      bw.Write(8.88);

      // Overwrite the first int with another value
      bw.Seek(0, SeekOrigin.Begin); // offset 0 relative to the beginning of the stream
      bw.Write(77);

      // Append the third float to the end.
      bw.Seek(0, SeekOrigin.End);
      bw.Write(100.05f);

      // Close streams
      bw.Close();
      fw.Close();

      // 2. Checking
      // Open the file "data.bin" for reading: fr <- data.bin
      FileStream fr = new FileStream("data.bin", FileMode.Open);

      // Create the stream adapter: br <- fr <- data.bin
      BinaryReader br = new BinaryReader(fr, Encoding.Default);

      // Read the integer
      int d = br.ReadInt32();

      // Read the double number
      double x = br.ReadDouble();

      // Read the float number
      float f = br.ReadSingle();

      // Print the result
      Console.WriteLine($"d = {d}"); // d = 77
      Console.WriteLine($"x = {x}"); // x = 8.88
      Console.WriteLine($"f = {f}"); // f = 100.05

      // Close streams
      bw.Close();
      fw.Close();
    }
  }
}

The result of the program

d = 77
x = 8.88
f = 100.05

 

4.3. The Flush() method. Example

The Flush() method is used to flush all buffers of the current writer. You can then write any buffered data to the device that you are currently allowed to write to.

In the most general case, a call to the Flush() method looks like this:

FileStream fs = new FileStream("file.dat", FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs, Encoding.Default);

...

bw.Flush();

...

bw.Close();
fs.Close();

 


Related topics