Read specific bytes of a file
49,171
Solution 1
LINQ Version:
byte[] test = File.ReadAllBytes(file).Skip(50).Take(10).ToArray();
Solution 2
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);
}
Solution 3
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
.
Solution 4
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;
}
}
Solution 5
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;
}
![Ahmed M. Taher](https://i.stack.imgur.com/hClA9.jpg?s=256&g=1)
Author by
Ahmed M. Taher
Updated on July 26, 2021Comments
-
Ahmed M. Taher almost 3 years
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.
-
Mesh over 12 yearsONLY because you edited the question...In the OP this was not clear.
-
Marc Gravell over 12 yearsYou 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.
-
Richard over 12 yearsI suggest you look at my edit. The file requirement was there (and I didn't change the title).
-
Marc Gravell over 12 yearsThe "offset" in the call to Read is the offset in the buffer, not the offset in the stream
-
oqx over 12 yearsnumBytesRead is the offset, the arguments goes (buffer,offset,count)
-
Marc Gravell over 12 yearsFrom 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."
-
Richard over 12 yearsOn 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 ofbytes
.) -
Marc Gravell over 12 yearsThe important thing is: the documentation explicitly reserved that right: so - I you don't, you aren't following the published API
-
the_joric over 12 yearsHere all file content will be read and then only 10 bytes will be used. Not very optimal approach :)
-
Marc Gravell over 12 yearsyou 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)
-
Richard over 12 years@the_joric However a helper that given a filename returned a lazy
IEnumerable<byte>
in place ofFile.ReadAllBytes
would be an effective approach, especially if reading an arbitrary run of bytes from a file was a common need. -
Tajomaru almost 11 yearsStream.Seek method takes two arguments. It should be
reader.BaseStream.Seek(50, SeekOrigin.Begin);
-
Nick Falco about 9 yearsWorked great! Thanks!
-
Phil Whittington about 6 years@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.
-
Richard about 6 years@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.
-
brthornbury almost 6 yearsThis is terrible, and defeats the entire purpose of reading from only part of the file.
-
Jee almost 4 yearsIs it just me or is this the better answer?
-
Soleil over 3 yearsThis solution does not allow multiple file access.
-
Soleil over 3 yearsUnlike Robert Rouhani'ssolution, this one do allow multiple file access.
-
Eli Davis about 2 yearsAnswers 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