6

I am trying to read data from binary file to an std::string.Here is what I have tried at first.

#include <iostream>
#include <string>
#include <fstream>

using namespace std;

int main(int argc, char const *argv[])
{
    fstream file("output.bin" , ios::out | ios::binary | ios::in);
    string my_str(5, '\0');
    file.read(my_str.c_str(), 5);
    cout << "String = " << my_str<< endl ;
}

And the compiler gave the error :

error: invalid conversion from ‘const char*’ to ‘std::basic_istream<char>::char_type* {aka char*}’ [-fpermissive]
  file.read(my_str.c_str(), 5);

As far as I understand, c_str() returns a const pointer which cannot be used in read method, so I changed my approach a little bit(which you can see below). Is there a better way to do this ?

#include <iostream>
#include <string>
#include <fstream>

using namespace std;

int main(int argc, char const *argv[])
{
    fstream file("output.bin" , ios::out | ios::binary | ios::in);
    string my_str(5, '\0');
    char buffer[6];
    file.read(buffer, 5);
    buffer[5] = '\0';
    my_str = string(buffer);

    cout << "String = " << my_str<< endl ;
}

ps : forgive me if I could not make myself clear, this is my first time here :)

2
  • I would use std::vector<char> or std::vector<uint8_t> instead of std::string Commented Jul 27, 2016 at 21:25
  • I could never understand why people use std::string for binary data. Keep in mind that this container's value_type is char, which may lead to problems related to sign extension (for example, think about what the result of my_str[3] == 0x95 will be). You might want to use std::vector<std::uint8_t>. Commented Jul 27, 2016 at 21:30

3 Answers 3

9

In C++11, the way to get a non-const pointer to the string's data is:

file.read(&my_str[0], 5);

C++17 will introduce non-const data() for this as well:

file.read(my_str.data(), 5);
Sign up to request clarification or add additional context in comments.

5 Comments

These quirks really make C++ great. A convenient non-const method to get the internal string buffer will be added 35 years late.
Just to be sure, the size of my_str before calling the read method should be greater than or equal to 5 , right ? @Barry
@baris_esmer Of course. All the usual caveats apply.
I think this invokes UB: cppreference.com says that "Modifying the past-the-end null terminator stored at data() + size() to any value other than CharT() has undefined behavior", and overwriting the first NUL does exactly that.
@ErikP. This isn't modifying data() + size(), string(5, '\0') has size 5 (not 0).
3

another way, using standard algorithms:

#include <iostream>
#include <string>
#include <fstream>
#include <algorithm>
#include <iterator>

using namespace std;

int main(int argc, char const *argv[])
{
    fstream file("output.bin" , ios::out | ios::binary | ios::in);

    auto my_str = string();

    copy_n(istream_iterator<char>(file), 
           5, 
           std::back_inserter(my_str));

    cout << "String = " << my_str<< endl ;
}

Comments

2

std::string is specially designed to work with strings and with c-style strings as well, so this fact will work against you in this situation. For example your code:

char buffer[6];
file.read(buffer, 5);
buffer[5] = '\0';
my_str = string(buffer);

what is wrong with it? You are reading binary data and who guarantees that there won't be '\0' byte there? You can fix it by:

my_str = string(buffer,5);

but this shows the point - std::string as a buffer is not a good choice. So you better use std::vector<char> or even better std::vector<uint8_t> which has method data() but will not implicitly convert from c-string, output to std::ostream etc.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.