0

I'm trying to generate a text file that has 50 lines, each line consisting of 50 spaces. However, every few lines, 9 or 10 extra bytes gets added to the file.

#include <iostream>
#include <fstream>
using namespace std;

void InitializeCanvas() {
    ofstream file("paint.txt");
    int b = 0;
    for (int i = 0; i < 50; i++) {
        for (int j = 0; j < 50; j++) {
            file << " ";
        }
        file << "\r\n";

        //these lines show where the pointer is and where it should be
        b += 52;
        int pointer = file.tellp();
        int difference = pointer - b;
        cout << pointer << " (" << (difference) << ")" << endl;
    }
    file.close();
}

int main() {
    InitializeCanvas();
    return 0;
}

On line 9, 9 extra bytes are added. On lines 19, there are 19 extra bytes. Same for 29, 39, and 49. No extra bytes are added except for on those lines. What could be causing that? This code was compiled using CodeBlocks 13.12.

rhynodegreat
  • 185
  • 1
  • 2
  • 5
  • By extra, what are you comparing to as the expected value? Are you expecting one byte per space and 50 bytes per line? – NitrogenReaction Sep 10 '15 at 23:22
  • 50 bytes for the spaces plus two bytes for "\r\n" at the end – rhynodegreat Sep 10 '15 at 23:30
  • How many extra bytes are being added to the lines? At the beginning you said 9 or 10, but then you said line 19 has 19 extra bytes. What's in those extra bytes -- are they random, are they spaces? – Barmar Sep 10 '15 at 23:31
  • If you're ever wondering what's going on in a file, you should open it in a hex editor. My understanding is that Code::Blocks has a hex editor plugin (or there are several freely available hex editors or text editors that support viewing in hex mode). – Michael Burr Sep 10 '15 at 23:48

2 Answers2

2

Edit: Since the question got some additional information, the explanation of this answer does not fit anymore completely - still the solution should work.

The extra bytes come from two mixed newlines per row (NL+CRLF). Let's take a look at the end of a line because \n is interpreted already\r\n in your compiler.

...  20     0D   0D   0A
... Space   NL   CR   LF

The solution is in the constructor of ofstream. It's in text mode.

explicit ofstream (const char* filename, ios_base::openmode mode = ios_base::out);

Just use \n or write your data in binary format, or use endl.

ofstream file("paint.txt", std::ios_base::binary | std::ios_base::out);
HelloWorld
  • 2,392
  • 3
  • 31
  • 68
  • Why would this only add extra bytes on lines 9, 19, 29, etc.? – Barmar Sep 10 '15 at 23:32
  • This seems like the right answer, but it doesn't fit with his description of the problem. Why would it add 9 bytes to line 9, instead of 1 byte to every line? – Barmar Sep 10 '15 at 23:34
  • Rather than `\n`, he probably should use `endl` if he's in text mode. – Barmar Sep 10 '15 at 23:36
  • 1
    The description which lines were causing issues were added after I wrote my answer. I tried this now and I can't confirm this. Your source creates a filesize of 2650 bytes = (50*50 spaces + 50*NL + 50 CLRF). With the corresponding binary mode the file has the expected size of 2600 bytes. I would recommend to use a debugger and step through the process and check the filepointer after each write. – HelloWorld Sep 10 '15 at 23:38
  • Isn't that what he's doing with `file.tellp()`? – Barmar Sep 10 '15 at 23:41
  • I would go char by char. Or is there a new edit of the question which says where the additional characters come from which I do miss? – HelloWorld Sep 10 '15 at 23:44
  • I'm still waiting for him to answer my question about what's in those additional characters. – Barmar Sep 10 '15 at 23:50
  • The discrepancy between every line being wrong and every 10th line being wrong may be related to buffering. Perhaps the newlines go into the buffer as a LF, and only when the buffer is flushed to disc are those converted to CR+LF. Suppose flushing happens when a sector's worth is buffered up, that's about 10 lines if your sectors are 512 bytes, at which point the cumulative error is 9 or ten extra LFs. On other machines, the sector size might be 4096, so the problem isn't seen. Perhaps the buffering and flushing behavior varies with the version of the library or OS. – Adrian McCarthy Sep 10 '15 at 23:58
  • Using a hex editor, the problem was indeed having `0D 0D 0A` at the end of every line, making each line 53 bytes long. Using `endl` generates the file correctly. As for the extra bytes, apparently they weren't actually being added to the file. The hex editor shows only the expected 53 bytes per line and the file size was 2650 bytes. Based on having one extra byte per line, I have no idea where the odd pattern came from. – rhynodegreat Sep 11 '15 at 00:11
  • The compiler is *not* the one who transforms `\n` to `\r\n`! This transformation is done in the standard library's stream implementation. Important difference. If the compiler was the one who did that transformation you would *not* be able to "turn it off" by `std::ios_base::binary`. – Paul Groke Sep 11 '15 at 00:51
0

Some (windows) compilers replace "\n" by "\r\n" so if you write "\r\n" you get the '\r' twice.

All you need to do is to use endl instead of the "\r\n"

replace this line:

file << "\r\n";

by:

file << endl;
SHR
  • 7,940
  • 9
  • 38
  • 57
  • The compiler is *not* the one who transforms `\n` to `\r\n`! This transformation is done in the standard library's stream implementation. Important difference. – Paul Groke Sep 11 '15 at 00:52