C# Seek

Note

Seek locates a position in a file. It allows data to be read from a binary file at a certain part. For example, we can read 20,000 bytes from any part of a file. This is useful for certain file formats—particularly binary ones.

Example

Arrow indicates movement

First, we look at how you can use the Seek method. From databases, you know that Seek is the term for when the data can be instantly retrieved, with an index. Therefore, Seek should be fast.

Here:This example gets the 50000th byte to the 51999th byte and iterates through them.

Note:The BinaryReader class is used. The program opens the binary file with BinaryReader here. It uses the "perls.bin" file.

File.Open
C# program that seeks in Main method

using System;
using System.IO;

class Program
{
    static void Main()
    {
	// 1.
	// Open as binary file.
	using (BinaryReader b = new BinaryReader(File.Open("perls.bin",
							   FileMode.Open)))
	{
	    // 2.
	    // Important variables:
	    int length = (int)b.BaseStream.Length;
	    int pos = 50000;
	    int required = 2000;
	    int count = 0;

	    // 3.
	    // Seek the required index.
	    b.BaseStream.Seek(pos, SeekOrigin.Begin);

	    // 4.
	    // Slow loop through the bytes.
	    while (pos < length && count < required)
	    {
		byte y = b.ReadByte();
		// 5.
		// Increment the variables.
		pos++;
		count++;
	    }
	}
    }
}
Byte type

Variables used in program. Length is the entire length of the file we are reading from. Pos is the index we want to start reading from. Required is the number of bytes we want to read. Count is the number of bytes we have read.

Seek:We call Seek on the BaseStream and move the position to 50000 bytes. It looks through each byte.

Performance optimization

The above code can slow down IO. It apparently requires each byte to be read separately off the disk. By using arrays, we can improve performance by several times. Next, we look at the version that uses arrays.

Example 2

We next use the Seek method with arrays of bytes. There are two useful methods you can call to read in an array of bytes. They are Read and ReadBytes.
Below we see ReadBytes,
but if you need to reuse your buffer,
use Read.

C# program that uses Seek and ReadBytes

using System;
using System.IO;

class Program
{
    static void Main()
    {
	// 1.
	// Open file with a BinaryReader.
	using (BinaryReader b = new BinaryReader(File.Open("perls.bin",
							   FileMode.Open)))
	{
	    // 2.
	    // Variables for our position.
	    int pos = 50000;
	    int required = 2000;

	    // 3.
	    // Seek to our required position.
	    b.BaseStream.Seek(pos, SeekOrigin.Begin);

	    // 4.
	    // Read the next 2000 bytes.
	    byte[] by = b.ReadBytes(required);
	}
    }
}
Program icon

The example opens the same binary file. We start at the same index in the file as the previous example (the 50000th byte). BinaryReader itself doesn't provide Seek, but you can use BaseStream with no damage.

And:It calls ReadBytes. This reads in the 2000 required bytes. These are stored in the byte array.

Note:If there aren't enough bytes left, the ReadBytes method does not throw exceptions.

Reusing byte[] buffers. The above code could be changed so you can provide your own buffer. This could cut down on memory usage and memory pressure in some situations. In a performance-sensitive application, this makes sense.

Discussion

Note

Here we look at two Read methods available on the BinaryReader class. They both will store the result in an array but with the Read method you can provide your own buffer, which can reduce memory usage in some scenarios.

BinaryReader.ReadBytes:Reads count bytes from the current stream into a byte array and advances the current position by count bytes.

ReadBytes: MSDN

BinaryReader.Read:Reads count bytes from the stream with index as the starting point in the byte array.

Read: MSDN

Benchmarks

Two

Here we compare the performance benchmarks of the first example shown in this article (which uses single byte reads) and the second example in this article (which uses arrays). The array example is much faster.

Note:This may occur because Windows doesn't buffer the single byte reads well. Also, there are different layers of code here.

Benchmark notes for Seek

Bytes read: 20000
File size: 2.94 MB
Start position: Inclusive random number
Compilation: Release
Iterations: 10000

Seek benchmark results

Read one byte: 2574 ms
Read array:     671 ms

Summary

The C# programming language

We used the Seek method on the BinaryReader and FileStream classes. The article showed the performance of using seeking with BinaryReader and FileStream. Using the array read method is far faster than using single bytes.

Finally:In my test with a three megabyte file, the amount of time executing the Seek wasn't significant.


C#: File