Q:

How does BytesIO.read() detect an end of file?

I’m trying to understand how BytesIO works. 
I’m trying to read a PostScript file from a PDF. When I convert the file to a string I read everything correctly except the end of it is gibberish. 
dup 116 /t put
dup 117 /u put
dup 118 /v put
dup 119 /w put
dup 120 /x put
dup 121 /y put
dup 122 /z put
readonly def
currentdict end
currentfile eexec
Ÿ÷oc;Ñj≤Ñº¯∞Aw-ÂŒ=”%ÂWò)-{ŸrΩu˙ï)ØúÇﬂrˆAï…¬‹„E(ı@⁄˝{Îπ¥á∫ìQª˚|¸_ëR—Âª
ÿ–∆œ§ÎA≥≈ -T@Ê|˝q|VÅkπøJ%†qu8P¢¯wƒGx≥≈™€ÃÜ÷ÂQÊØ6K¸™“-çUå\Åß‘%°bù’"t-*x‘ıˆ”üœˇJë+
}Ïç3•{Z‡2é˘’z›¨T2s¿$ZıÃ—&{BËñJ◊{®•ﬂrÃó’ΩÕ·mî1lË(zÂNR¯rÈÚ^&%œ:(/Iãåﬂ∫Hímß!í4ù‹JﬂxIÚ7πbs,OíiˇOl7≥5R9Â¡˙ü≥zË(≤X*áRhï≥n√5áü≥&à£Âg«¸çﬁ\«c› ›µ∏9`EπΩÄ‚gú≤wÅÈ›T!…‹x»I‘ÒJz“àvÈ„*lÙcõo∆øÊÕsdm^ï%µµÇ=Ë∞∫ïüD+ã≥ùuˆ9πç#ïúö†π3µP«_]≤ÂÎ)õØËª≈w
¯à≈Í„™U™ˇAØ≠†8ú§  Hèé˘∑á·ÕuG–·:Dﬁá·Jàé˛(Ü¢ÛW≠¬ÛÕæÛÔ]£-0<.™gSBNlîZûOêLÔ”°é5^9¥√˛:ßK∫*|ÓF
ÇÑˇ{√â ⁄áÄ™÷E,ﬂû˚qº>Ωj0^óxÎñ≤Q≈˛'X√ÈÌÈÖâºi…;yZ…Pıt∏„¢>ˇ±ÿ‹pÁ1ÅSV∞}è«:¶¿ﬁ™aÛd0hƒ◊{<m’2wÌÃüñ˙ÜÖg5∆~Çñ»Ô

When I do BytesIO.read() in Python it somehow knows that there is gibberish and removes it.
My question is how does it know? Is there an end of file character that it looks for? If so what is it? 

A:

Yes, some systems do have an end-of-file character. MS-DOS used the ^Z (b'\x1a') in text files to signify the end of file. If the file was opened in binary mode, this wouldn't be the case. In UNIX, the ^D (b'\x04') (can be used on terminal to signify the end-of-file for text that is entered from terminal; however it is not something that is written to a file; there is no end marker.
Instead of any magic character, the EOF, or end-of-file, is usually just a condition. The operating system knows how big each file are, and keeps track on where each open file is being read. Now, if the read position on some file is at 1000 (0-based) and the file is 1000 bytes long, and you try to read more, the operating system will say EOF instead of giving you more bytes.
Now of course this again does not apply at all to BytesIO either, because it is not a file, but an emulation thereof. BytesIO(data) behaves like a readable file whose size would be len(data) and that would have the bytes of data; but there is no actual file anywhere; with BytesIO Python just emulates how an operating system would behave should it be a file like that. Thus the .read(), given no arguments there always returns all the data from current "file" position to the end of "file", that is, the splice data[current_file_position:].

