Reading a string from a file in C++

不问归期 提交于 2021-02-07 09:40:07

问题


I'm trying to store strings directly into a file to be read later in C++ (basically for the full scope I'm trying to store an object array with string variables in a file, and those string variables will be read through something like object[0].string). However, everytime I try to read the string variables the system gives me a jumbled up error. The following codes are a basic part of what I'm trying.

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

/*
//this is run first to create the file and store the string
int main(){
    string reed;
    reed = "sees";
    ofstream ofs("filrsee.txt", ios::out|ios::binary);
    ofs.write(reinterpret_cast<char*>(&reed), sizeof(reed));
    ofs.close();

}*/

//this is run after that to open the file and read the string
int main(){
    string ghhh;
    ifstream ifs("filrsee.txt", ios::in|ios::binary);
    ifs.read(reinterpret_cast<char*>(&ghhh), sizeof(ghhh));
    cout<<ghhh;
    ifs.close();
    return 0;
}

The second part is where things go haywire when I try to read it. Sorry if it's been asked before, I've taken a look around for similar questions but most of them are a bit different from what I'm trying to do or I don't really understand what they're trying to do (still quite new to this).


回答1:


What am I doing wrong?

You are reading from a file and trying to put the data in the string structure itself, overwriting it, which is plain wrong.

As it can be verified at http://www.cplusplus.com/reference/iostream/istream/read/ , the types you used were wrong, and you know it because you had to force the std::string into a char * using a reinterpret_cast.

C++ Hint: using a reinterpret_cast in C++ is (almost) always a sign you did something wrong.

Why is it so complicated to read a file?

A long time ago, reading a file was easy. In some Basic-like language, you used the function LOAD, and voilà!, you had your file. So why can't we do it now?

Because you don't know what's in a file.

  • It could be a string.
  • It could be a serialized array of structs with raw data dumped from memory.
  • It could even be a live stream, that is, a file which is appended continuously (a log file, the stdin, whatever).
  • You could want to read the data word by word
  • ... or line by line...
  • Or the file is so large it doesn't fit in a string, so you want to read it by parts.
  • etc..

The more generic solution is to read the file (thus, in C++, a fstream), byte per byte using the function get (see http://www.cplusplus.com/reference/iostream/istream/get/), and do yourself the operation to transform it into the type you expect, and stopping at EOF.

The std::isteam interface have all the functions you need to read the file in different ways (see http://www.cplusplus.com/reference/iostream/istream/), and even then, there is an additional non-member function for the std::string to read a file until a delimiter is found (usually "\n", but it could be anything, see http://www.cplusplus.com/reference/string/getline/)

But I want a "load" function for a std::string!!!

Ok, I get it.

We assume that what you put in the file is the content of a std::string, but keeping it compatible with a C-style string, that is, the \0 character marks the end of the string (if not, we would need to load the file until reaching the EOF).

And we assume you want the whole file content fully loaded once the function loadFile returns.

So, here's the loadFile function:

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

bool loadFile(const std::string & p_name, std::string & p_content)
{
    // We create the file object, saying I want to read it
    std::fstream file(p_name.c_str(), std::fstream::in) ;

    // We verify if the file was successfully opened
    if(file.is_open())
    {
        // We use the standard getline function to read the file into
        // a std::string, stoping only at "\0"
        std::getline(file, p_content, '\0') ;

        // We return the success of the operation
        return ! file.bad() ;
    }

    // The file was not successfully opened, so returning false
    return false ;
}

If you are using a C++11 enabled compiler, you can add this overloaded function, which will cost you nothing (while in C++03, baring optimizations, it could have cost you a temporary object):

std::string loadFile(const std::string & p_name)
{
    std::string content ;
    loadFile(p_name, content) ;
    return content ;
}

Now, for completeness' sake, I wrote the corresponding saveFile function:

bool saveFile(const std::string & p_name, const std::string & p_content)
{
    std::fstream file(p_name.c_str(), std::fstream::out) ;

    if(file.is_open())
    {
        file.write(p_content.c_str(), p_content.length()) ;

        return ! file.bad() ;
    }

    return false ;
}

And here, the "main" I used to test those functions:

int main()
{
    const std::string name(".//myFile.txt") ;
    const std::string content("AAA BBB CCC\nDDD EEE FFF\n\n") ;

    {
        const bool success = saveFile(name, content) ;
        std::cout << "saveFile(\"" << name << "\", \"" << content << "\")\n\n"
                  << "result is: " << success << "\n" ;
    }

    {
        std::string myContent ;
        const bool success = loadFile(name, myContent) ;

        std::cout << "loadFile(\"" << name << "\", \"" << content << "\")\n\n"
                  << "result is: " << success << "\n"
                  << "content is: [" << myContent << "]\n"
                  << "content ok is: " << (myContent == content)<< "\n" ;
    }
}

More?

If you want to do more than that, then you will need to explore the C++ IOStreams library API, at http://www.cplusplus.com/reference/iostream/




回答2:


You can't use std::istream::read() to read into a std::string object. What you could do is to determine the size of the file, create a string of suitable size, and read the data into the string's character array:

std::string str;
std::ifstream file("whatever");
std::string::size_type size = determine_size_of(file);
str.resize(size);
file.read(&str[0], size);

The tricky bit is determining the size the string should have. Given that the character sequence may get translated while reading, e.g., because line end sequences are transformed, this pretty much amounts to reading the string in the general case. Thus, I would recommend against doing it this way. Instead, I would read the string using something like this:

std::string   str;
std::ifstream file("whatever");
if (std::getline(file, str, '\0')) {
     ...
}

This works OK for text strings and is about as fast as it gets on most systems. If the file can contain null characters, e.g., because it contains binary data, this doesn't quite work. If this is the case, I'd use an intermediate std::ostringstream:

std::ostringstream out;
std::ifstream      file("whatever");
out << file.rdbuf();
std::string str = out.str();



回答3:


A string object is not a mere char array, the line

ifs.read(reinterpret_cast<char*>(&ghhh), sizeof(ghhh));

is probably the root of your problems.

try applying the following changes:

char[BUFF_LEN] ghhh;
....
ifs.read(ghhh, BUFF_LEN);


来源:https://stackoverflow.com/questions/12340402/reading-a-string-from-a-file-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!