C# checking for binary reader end of file
Asked Answered
P

5

61

I was searching for a way to check whether I've reached the end of a file for my binary reader and one suggestion was to use PeekChar as such

while (inFile.PeekChar() > 0)
{
    ...
}

However, it looks like I've run into an issue

Unhandled Exception: System.ArgumentException: The output char buffer is too sma
ll to contain the decoded characters, encoding 'Unicode (UTF-8)' fallback 'Syste
m.Text.DecoderReplacementFallback'.
Parameter name: chars
   at System.Text.Encoding.ThrowCharsOverflow()
   at System.Text.Encoding.ThrowCharsOverflow(DecoderNLS decoder, Boolean nothin
gDecoded)
   at System.Text.UTF8Encoding.GetChars(Byte* bytes, Int32 byteCount, Char* char
s, Int32 charCount, DecoderNLS baseDecoder)
   at System.Text.DecoderNLS.GetChars(Byte* bytes, Int32 byteCount, Char* chars,
 Int32 charCount, Boolean flush)
   at System.Text.DecoderNLS.GetChars(Byte[] bytes, Int32 byteIndex, Int32 byteC
ount, Char[] chars, Int32 charIndex, Boolean flush)
   at System.Text.DecoderNLS.GetChars(Byte[] bytes, Int32 byteIndex, Int32 byteC
ount, Char[] chars, Int32 charIndex)
   at System.IO.BinaryReader.InternalReadOneChar()
   at System.IO.BinaryReader.PeekChar()

So maybe PeekChar isn't the best way to do it, and I don't think it should even be used that way because I'm checking the current position of my reader and not really what the next character is supposed to be.

Petulance answered 8/6, 2012 at 3:48 Comment(2)
Use StreamReader (char stream) to read the Text file. I'd suggest BinaryReader.ReadBytes(nBytes_to_be_read) if you want to read a file.Empiric
Depending on your specific code and whether the file access is shared, you may also be able to cache the stream's .Length property to a local variable, which will optimize and improve the performance even more.Ingrained
P
109

There is a more accurate way to check for EOF when working with binary data. It avoids all of the encoding issues that come with the PeekChar approach and does exactly what is needed: to check whether the position of the reader is at the end of the file or not.

while (inFile.BaseStream.Position != inFile.BaseStream.Length)
{
   ...
}
Petulance answered 6/8, 2013 at 15:12 Comment(6)
Note that Position and Length are properties, not methods, of the Stream class. Unless you've defined extension methods with those same names, the method call syntax won't compile.Kingcraft
Thanks, I'm not sure why I wrote them as methods before.Petulance
This only works if the underlying Stream supports seeking.Silvas
@Silvas So does PeekChar, so that's not really a difference :)Carolanncarole
@Silvas unless I'm mistaken the ability to seek is not the same as the ability to read length and position of a stream. Though, usually a fixed length stream will be seekable.Mcmillen
Depending the underlying stream, calling BaseStream.Length might be really slow. FileStream for eg, will call Win32.GetFileSize() each time. If you know length is not going to change, you might want to cache it first (eg : in a local var)Deoxidize
T
8

I suggest very similar to @MxLDevs, but with a '<' operator rather than a '!=' operator. As it is possible to set Position to anything you want (within long confines), this will stop any attempts to access an invalid file Position by the loop.

while (inFile.BaseStream.Position < inFile.BaseStream.Length)
{
   ...
}
Thant answered 21/8, 2020 at 10:54 Comment(0)
C
6

Wrapping it into a Custom Extension Method that'll extend the BinaryReader class by adding the missing EOF method.

public static class StreamEOF {

    public static bool EOF( this BinaryReader binaryReader ) {
        var bs = binaryReader.BaseStream;
        return ( bs.Position == bs.Length);
    }
}

So now you can just write:

while (!infile.EOF()) {
   // Read....
}

:) ... assuming you have created infile somewhere like this:

var infile= new BinaryReader();

Note: var is implicit typing. Happy to found it - it's other puzzle piece for well styled code in C#. :D

Conchitaconchobar answered 22/10, 2015 at 3:0 Comment(1)
wrong, very wrong. should be return ( bs.Position == bs.Length); and !infile.EOF()Pyrolysis
C
3

This work for me:

using (BinaryReader br = new BinaryReader(File.Open(fileName,   
FileMode.Open))) {
            //int pos = 0;
            //int length = (int)br.BaseStream.Length;
            while (br.BaseStream.Position != br.BaseStream.Length) {
                string nume = br.ReadString ();
                string prenume = br.ReadString ();
                Persoana p = new Persoana (nume, prenume);
                myArrayList.Add (p);
                Console.WriteLine ("ADAUGAT XXX: "+ p.ToString());
                //pos++;
            }
        }
Champac answered 26/7, 2016 at 16:19 Comment(0)
B
3

I'll add my suggestion: if you don't need the "encoding" part of the BinaryReader (so you don't use the various ReadChar/ReadChars/ReadString) then you can use an encoder that won't ever throw and that is always one-byte-per-char. Encoding.GetEncoding("iso-8859-1") is perfect for this. You pass it as a parameter of the BinaryReader constructor. The iso-8859-1 encoding is a one-byte-per-character encoding that maps 1:1 all the first 256 characters of Unicode (so the byte 254 is the char 254 for example)

Burkett answered 4/4, 2017 at 12:53 Comment(3)
One of the comments addressed an issue with streams that don't support seeking wouldn't support checking the length of the stream directly. I suppose this may resolve that issue under such circumstances.Petulance
@MxyL No, it won't solve that problem. The PeekChar() does a Read() and then uses the Position to rollback the Read().Burkett
For clarity, what would be the suggested approach to checking the end of the file with a specific encoding?Petulance

© 2022 - 2024 — McMap. All rights reserved.