0

I read a text file and it works very well.

std::string str_buf = "";
FILE *file = fopen("/home/pi/log_2019-03-07.txt", "r");
if (file != NULL)
{
    while (true)
    {
        char buffer[MAX_BUFFER_SIZE] = { 0x00, };
        size_t rSize = fread(buffer, MAX_BUFFER_SIZE, sizeof(char), file);

        str_buf += buffer;

        if (rSize == 0)
            break;
    }

    printf("%s", str_buf.data());
    fclose(file);
}

Then I try to write it to same path, another name. This is the code:

FILE *writefile = fopen("/home/pi/WriteTest.txt", "wb");
if (writefile != NULL)
{
    int offset = 0;
    while (true)
    {
        size_t wSize = fwrite(&str_buf.data()[offset], sizeof(char), strlen(str_buf.data()) - 1, writefile);

        offset += (int)wSize;

        if (offset >= strlen(str_buf.data()))
            break;
    }
    fclose(writefile);
}

If I try to execute this code, it works. I open WriteTest.txt, it has same string. It's perfectly same.
But I found WriteTest.txt's volume is almost 2 twice read text.

Why it happens?

Retalia K
  • 64
  • 9
  • 1
    *But I found 'WriteTest.txt''s volume is almost 2 twice read text.* How do you get the volume of the file? – R Sahu Mar 14 '19 at 04:55
  • 2
    When you read use use mode `"r"`, when you write you use mode `"wb"`. That could lead to differences. – Some programmer dude Mar 14 '19 at 04:55
  • Then your use of `str_buf` (what I assume is a `std::string` object) when writing seems weird. And why aren't you really checking for errors when both reading and writing? – Some programmer dude Mar 14 '19 at 04:57
  • [My files go up to 11.](https://www.youtube.com/watch?v=DzLP2Z7JVZA) Retalia, do you perhaps mean the size of the file, the number of bytes in the file? – user4581301 Mar 14 '19 at 04:57
  • 1
    You are writing one `char` less in `strlen(str_buf.data()) - 1` – doptimusprime Mar 14 '19 at 04:58
  • volume means it's capacity. I saw that in GUI on Raspbian. – Retalia K Mar 14 '19 at 05:01
  • Oh and most importantly of all: You don't write the string null terminator, but when you read you read the file as though the null terminator is in it (possibly in multiple places depending on the size of the file and the value of `MAX_BUFFER_SIZE`). – Some programmer dude Mar 14 '19 at 05:03
  • I think 'std::string += char*' makes '\0' automatically. It's wrong? – Retalia K Mar 14 '19 at 05:05
  • 1
    But the contents in `buffer` might *not* be null-terminated. If a call to `fread` fills the *whole* of `buffer` there's no null-terminator in it. Then treating `buffer` as a null-terminated byte string is wrong. – Some programmer dude Mar 14 '19 at 05:06
  • You are right. buffer has not null-terminated. But if string += operation does not create '\0', it will be crashed in 'printf' I think. – Retalia K Mar 14 '19 at 05:10
  • Oh, I solved this problem thanks for answer – Retalia K Mar 14 '19 at 05:12
  • When you do `str_buf += buffer`, then the `+=` operator needs to find the end of the string in `buffer`. It does that by searching for the `'\0'` character, the null-terminator. If it's not found then you will go out of bounds of `buffer` in search of the terminator. That leads to [*undefined behavior*](https://en.wikipedia.org/wiki/Undefined_behavior), which in some cases can cause crashes, but it doesn't have to. And since the C++11 standard, all strings in a `std::string` object will be terminated so `printf` won't have any problem with it. – Some programmer dude Mar 14 '19 at 05:13
  • That makes sense. I understand what you say now. – Retalia K Mar 14 '19 at 05:15
  • Lastly, *please* [get a couple of good books](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list/388282#388282) and learn "proper" C++, using `std::cout` and the [C++ standard I/O library with streams](https://en.cppreference.com/w/cpp/io). – Some programmer dude Mar 14 '19 at 05:15
  • @Someprogrammerdude some authors prefer not to use iostreams for unformatted I/O (or even formatted I/O) – M.M Mar 14 '19 at 05:44

1 Answers1

1
size_t wSize = fwrite(&str_buf.data()[offset], sizeof(char), strlen(str_buf.data()) - 1, writefile);

you start writing the text at offset &str_buf.data()[offset] but you write the length of a string starting at position 0. You are writing offset bytes too much. You should

size_t wSize = fwrite(&str_buf.data()[offset], sizeof(char), 
                      strlen(str_buf.data()) - offset, writefile);

Also, you don't write string length nor a NUL terminator. So you'd have trouble figuring out how much to read unless, like in your simple example, it is at file's end.

And last, it's better to use str_buf.length() rather than strlen. It's faster and works with strings that have NUL in the middle.

Michael Veksler
  • 8,217
  • 1
  • 20
  • 33