8
votes

This may properly belong to a different part of Stack Exchange but I don't think so - programmers.se is more about other things.

Getting to the question: There are things you can do with std::ios::binary that you cannot do in text mode (E.g. relative seek) but I cannot find anything to do in text mode that you cannot do in binary mode - even reading the file as text with e.g. std::getline()

So why would I ever open as text? As a perhaps-related question, why not open as binary by default? Whose use-case does that break?

EDIT Additional information

Here's what's causing me to ask:

I have a file which is created on a windows system - that is, the line-endings are CR LF.

I am opening it with std::ifstream using the std::ios::binary flag

I am parsing through the file with std::getline and getting exactly the behavior I would expect - getline reads one line at a time.

System: Windows 7 Pro

Compiler: g++ for MINGW32

2
Not sure if the standard library does this, but there can be some text encoding bytes and byte order masks at the beginning of a text file. Maybe the standard library interprets them correctly and skips them if opened in text mode? But treats them as non-special bytes in binary mode? - leemes
There used to be this idea that you would read and write "a text file" platform-agnostically. So you want to use whatever line separator is suitable for the platform. For those who use any text editor other than Notepad on Windows, I think this idea has pretty much had its day -- you can write LF only and accept both kinds of linebreak when reading, on any platform. But even if you accept that (which not everyone will), changing the default is a needless incompatibility. - Steve Jessop
@medivh: on Windows, opening a file in text mode means that if the file contains \r\n it will be read as \n. So code that uses the default and expects to see \n would be broken. It will instead see \r\n. So for example you could end up with a trailing \r on a value read from the file, because removing \n no longer removes the whole linebreak sequence. It will fail to match the equivalent value without the erroneous \r from some other source. - Steve Jessop
@medivh: so to be clear: because you have some code that works when it sees \r, you're almost entirely sure that no valid code exists that would not work when it sees \r? I don't think the follows ;-) Or do you mean you don't believe that opening a file that contains \r in binary mode will result in the code seeing the \r characters? That's easily confirmed with a few lines of test code. - Steve Jessop
@medivh He is certainly not wrong. In the last couple of years, I've had to parse files which were written on Windows, parsing on a Unix machine, and the extra '\r' did cause me extra work. - James Kanze

2 Answers

7
votes

What can you do in text mode that you can't do in binary? Read text, for starters. A file opened in text mode automatically translates between the '\n' character internally, and whatever the system uses to delimit lines in files externally. It can also recognize an arbitrary end of file, even when the underlying system requires file sizes to be a multiple of some fixed size.

The choice today is somewhat complicated by the fact that you often have to access the files from incompatible systems. If you have a file system mounted on both Windows and Unix, write it as text under Windows, and read it as text under Unix, then you'll see extra characters. In such cases, it may be preferable to read and write binary, and to do the line end handling yourself, according to whatever conventions you prefer. Similarly, if the "file" is actually a socket, communicating with another machine, you'll want to open it in binary, and handle line endings yourself, according to the requirements of the protocol.

2
votes

Well stdin is opened by default in text mode, this allows the use of for example CTRL + Z to signal EOF so I don't see why you think there is no "need" to have streams opened in anyting except binary mode.