0

I'm very unsure of file IO when it comes to this, and I'm really confused. When I use the insertion stream operator to push some short integers into the file the size of the file is not what I expect:

std::ofstream outFile("myFile.raw", std::ios::binary | std::ios::out);

std::vector<short> list;
for (int i = 0; i < 100; ++i) list.push_back(1);
for (auto i : list) outFile << i;
outFile.close();

This creates a file that is 100 bytes big. I'm not understanding, the short is supposed to be two bytes. The documentation shows that the << operator is overloaded for many different types, so I thought that this writes the correct data type. I guess not.

Thanks.

Zebrafish
  • 11,682
  • 3
  • 43
  • 119
  • 3
    Use *UnformattedOutputFunction* for binary files, i.e [`std::ofstream::write`](http://en.cppreference.com/w/cpp/io/basic_ostream/write). Also take Endianess into consideration if the binary file is to be used in other platforms – WhiZTiM Jan 17 '17 at 21:46
  • 1
    `<<` prints the number as a string, not its internal representation. So it's just writing `1` every time. – Barmar Jan 17 '17 at 21:47
  • Isn't that what you see if you do `cout << i;`? Don't you expect the file to contain the same thing? – Barmar Jan 17 '17 at 21:47
  • 1
    use `outFile.write(&i, 2);` – Stephan Lechner Jan 17 '17 at 21:50
  • @Barmar Ummm, well no, I didn't, truth is I have no idea. I thought setting the ios::binary flag would have done something like that. I mean made it unformatted as opposed to working with strings. – Zebrafish Jan 17 '17 at 21:50
  • @Titone The binary flag simply says how things like line-ending characters are to be treated; it doesn't magically turn the stream into binary. –  Jan 17 '17 at 21:52
  • @latedeveloper that is what "turn the stream into binary" means – M.M Jan 17 '17 at 22:01
  • @M.M By turning it into binary I meant (for example) writing out each int as (on a 32-bit system) 4 bytes. –  Jan 17 '17 at 22:10
  • What does the internal file format in which a `short` happens to be stored on your platform have to do with any file format? – David Schwartz Jan 17 '17 at 22:16

2 Answers2

4

You are using formatted output.

The short ints are written as digits. Each digit is 1 which is a single char of a single byte.

So the total is 100. If you had short ints containing double digit numbers, say 22, then the size would be 200.


As an alternative you could either use unformatted output or you could cast the data to chars, which together with the binary flag you have set will write the data without formatting it. Something to keep in mind when writing raw chars is that you will have to consider how many bytes and how you want to order the bytes in the file.


Formatted output and input could be more convenient in general. As an alternative to writing the file with raw chars it would be better to look into serialization.

Community
  • 1
  • 1
wally
  • 10,717
  • 5
  • 39
  • 72
  • Thank you. I thought setting the ios::binary flag would have made it work. I'm really clueless about this. – Zebrafish Jan 17 '17 at 21:52
  • @TitoneMaurice If you think about it, that would mean that `operator<<` would have to interrogate the stream mode and produce completely different output (in one case a number, in another case a native representation of a number) based on that mode. That really would be an illogical design. – David Schwartz Jan 17 '17 at 22:21
1

The reason is - as mentioned in the comments an in the previous answer - that operator << is formatted output and writes value 1 as a single digit (which consists of only one character).

Just for the sake of showing how a short int could be written as binary, see the following code:

std::ofstream outFile("myFile.raw", std::ios::binary | std::ios::out);

std::vector<short> list;
for (int i = 0; i < 100; ++i) list.push_back(1);
for (auto i : list) outFile.write((const char*)&i, sizeof(i));
outFile.close();

std::ifstream in("myFile.raw", std::ifstream::ate | std::ifstream::binary);
std::cout << "File size: " <<  in.tellg() << std::endl;
// prints out: File size: 200
in.close();
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58