43

Is there any way to read specific bytes from a file?

For example, I have the following code to read all the bytes of the file:

byte[] test = File.ReadAllBytes(file);

I want to read the bytes from offset 50 to offset 60 and put them in an array.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Ahmed M. Taher
  • 663
  • 1
  • 7
  • 15

7 Answers7

81

Create a BinaryReader, read 10 bytes starting at byte 50:

byte[] test = new byte[10];
using (BinaryReader reader = new BinaryReader(new FileStream(file, FileMode.Open)))
{
    reader.BaseStream.Seek(50, SeekOrigin.Begin);
    reader.Read(test, 0, 10);
}
Robert Rouhani
  • 14,512
  • 6
  • 44
  • 59
33

This should do it

var data = new byte[10];
int actualRead;

using (FileStream fs = new FileStream("c:\\MyFile.bin", FileMode.Open)) {
    fs.Position = 50;
    actualRead = 0;
    do {
        actualRead += fs.Read(data, actualRead, 10-actualRead);
    } while (actualRead != 10 && fs.Position < fs.Length);
}

Upon completion, data would contain 10 bytes between file's offset of 50 and 60, and actualRead would contain a number from 0 to 10, indicating how many bytes were actually read (this is of interest when the file has at least 50 but less than 60 bytes). If the file is less than 50 bytes, you will see EndOfStreamException.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 2
    You are meant to always check the return value of Read and loop as necessary. It is legal for Read to return 1 even when another 20000 bytes are available. – Marc Gravell Dec 30 '11 at 11:36
  • 1
    From FilStream.Read on MSDN: " An implementation is free to return fewer bytes than requested even if the end of the stream has not been reached." – Marc Gravell Dec 30 '11 at 11:43
  • The important thing is: the documentation explicitly reserved that right: so - I you don't, you aren't following the published API – Marc Gravell Dec 30 '11 at 11:50
  • you still aren't updating pos correctly; imagine it returns 1 byte each time... That means you overrwrite offset 1 each time (except the first) **and** tell it to read to much data (10 - pos) – Marc Gravell Dec 30 '11 at 12:20
  • Unlike Robert Rouhani'ssolution, this one do allow multiple file access. – Soleil Jan 11 '21 at 22:52
6

LINQ Version:

byte[] test = File.ReadAllBytes(file).Skip(50).Take(10).ToArray();
user703016
  • 37,307
  • 8
  • 87
  • 112
  • 71
    Here all file content will be read and then only 10 bytes will be used. Not very optimal approach :) – the_joric Dec 30 '11 at 11:56
  • 1
    @the_joric However a helper that given a filename returned a lazy `IEnumerable` in place of `File.ReadAllBytes` would be an effective approach, especially if reading an arbitrary run of bytes from a file was a common need. – Richard Dec 30 '11 at 13:51
  • 1
    @Richard -- not really. The Linq Skip method still iterates through those bytes; it just doesn't doesn't "yield" them up to the callng method. You really want to make a request to read from the offset directly. Using bespoke API calls for each OS will be the fastest solution, although the questioner may want a pure .Net approach for peace of mind. – Phil Whittington Jun 01 '18 at 17:13
  • @PhilWhittington Won't matter in this case, everything is in the first block of the file, so there will be a single read of data from the file either way. – Richard Jun 01 '18 at 18:24
  • 6
    This is terrible, and defeats the entire purpose of reading from only part of the file. – brthornbury Aug 04 '18 at 23:39
  • 2
    Answers like this are why LINQ has such a bad reputation for performance. 9 upvotes too meaning people have implemented this solution. Now there's some innocent-looking util function waiting to tank an application when it's requested to load in a small portion of a file, while the file itself is larger than the RAM of the computer. Poor one out for the homies having to debug that crash – Eli Davis May 15 '22 at 15:32
3

You need to:

  • seek to the data you want
  • call Read repeatedly, checking the return value, until you have all the data you need

For example:

public static byte[] ReadBytes(string path, int offset, int count) {
    using(var file = File.OpenRead(path)) {
        file.Position = offset;
        offset = 0;
        byte[] buffer = new byte[count];
        int read;
        while(count > 0  &&  (read = file.Read(buffer, offset, count)) > 0 )
        {
            offset += read;
            count -= read;
        }
        if(count < 0) throw new EndOfStreamException();
        return buffer;     
    }
}
gwt
  • 2,331
  • 4
  • 37
  • 59
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
0
using System.IO;

public static byte[] ReadFile(string filePath)
{
    byte[] buffer;
    FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
    try
    {
        buffer = new byte[length];            // create buffer
        fileStream.Read(buffer, 50, 10);
     }
     finally
     {
         fileStream.Close();
     }
     return buffer;
 }
DonCallisto
  • 29,419
  • 9
  • 72
  • 100
0

You can use filestream to and then call read

string pathSource = @"c:\tests\source.txt";

using (FileStream fsSource = new FileStream(pathSource,
    FileMode.Open, FileAccess.Read))
{

    // Read the source file into a byte array.
    byte[] bytes = new byte[fsSource.Length];
    int numBytesToRead = 10;
    int numBytesRead = 50;
    // Read may return anything from 0 to numBytesToRead.
    int n = fsSource.Read(bytes, numBytesRead, numBytesToRead);
}

Check this example MSDN

oqx
  • 2,157
  • 17
  • 27
  • numBytesRead is the offset, the arguments goes (buffer,offset,count) – oqx Dec 30 '11 at 11:39
  • 2
    On the other hand, the second param of [`FileStream.Read`](http://msdn.microsoft.com/en-us/library/system.io.filestream.read.aspx) is the offset into the *array* passed as the first parameter and not the offset in the *file*. So actually I was correct! :-) (As it stands the code will throw because index 50 is beyond the end of `bytes`.) – Richard Dec 30 '11 at 11:45
-3
byte[] a = new byte[60];
byte[] b = new byte[10];
Array.Copy( a ,50, b , 0 , 10 );
Mesh
  • 6,262
  • 5
  • 34
  • 53