50

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.

7 Answers 7

86

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); } 
Sign up to request clarification or add additional context in comments.

3 Comments

Stream.Seek method takes two arguments. It should be reader.BaseStream.Seek(50, SeekOrigin.Begin);
Is it just me or is this the better answer?
This solution does not allow multiple file access.
34

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.

5 Comments

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.
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."
The important thing is: the documentation explicitly reserved that right: so - I you don't, you aren't following the published API
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)
Unlike Robert Rouhani'ssolution, this one do allow multiple file access.
5

LINQ Version:

byte[] test = File.ReadAllBytes(file).Skip(50).Take(10).ToArray(); 

6 Comments

Here all file content will be read and then only 10 bytes will be used. Not very optimal approach :)
@the_joric However a helper that given a filename returned a lazy IEnumerable<byte> 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 -- 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.
This is terrible, and defeats the entire purpose of reading from only part of the file.
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
|
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; } } 

Comments

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

1 Comment

The "offset" in the call to Read is the offset in the buffer, not the offset in the stream
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

2 Comments

numBytesRead is the offset, the arguments goes (buffer,offset,count)
On the other hand, the second param of FileStream.Read 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.)
-3
byte[] a = new byte[60]; byte[] b = new byte[10]; Array.Copy( a ,50, b , 0 , 10 ); 

2 Comments

ONLY because you edited the question...In the OP this was not clear.
I suggest you look at my edit. The file requirement was there (and I didn't change the title).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.