【问题标题】:Reading a string from a file in C++从 C++ 文件中读取字符串
【发布时间】:2012-09-09 15:31:37
【问题描述】:

我正在尝试将字符串直接存储到文件中,以便稍后在 C++ 中读取(基本上对于完整范围,我正在尝试将带有字符串变量的对象数组存储在文件中,并且这些字符串变量将被读取像对象[0].string)。但是,每次我尝试读取字符串变量时,系统都会给我一个混乱的错误。以下代码是我正在尝试的基本部分。

#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;
}

第二部分是当我尝试阅读它时出现问题的地方。 抱歉,如果以前有人问过,我已经环顾四周寻找类似的问题,但其中大多数与我正在尝试做的事情有点不同,或者我真的不明白他们想要做什么(仍然很新手)。

【问题讨论】:

  • reinterpret_cast&lt;char *&gt;(&amp;reed) 看起来不对。为什么不reed.c_str()
  • 你为什么把它读成二进制?为什么不使用重载的&gt;&gt; 运算符?
  • 我使用 reinterpret_case 和二进制代码将对象保存在文件中。类似 (reinterpret_cast(&object). string 需要完全不同的方法吗?
  • (显然答案是我在第一条评论中建议的内容:)

标签: c++ string file-io fstream


【解决方案1】:

我做错了什么?

您正在从文件中读取数据并尝试将数据放入字符串结构本身,然后覆盖它,这是完全错误的。

因为可以在 http://www.cplusplus.com/reference/iostream/istream/read/ 进行验证,所以您使用的类型是错误的,并且您知道这一点,因为您必须使用 reinterpret_caststd::string 强制转换为 char *

C++ 提示:在 C++ 中使用 reinterpret_cast(几乎)总是表明您做错了。

为什么读取文件这么复杂?

很久以前,读取文件很容易。在一些类似 Basic 的语言中,您使用了函数 LOAD,并且瞧!,您有了自己的文件。 那么为什么我们现在不能这样做呢?

因为你不知道文件里有什么。

  • 它可能是一个字符串。
  • 它可能是一个序列化的结构数组,其中包含从内存中转储的原始数据。
  • 它甚至可以是实时流,即连续附加的文件(日志文件、标准输入等)。
  • 您可能希望逐字读取数据
  • ...或逐行...
  • 或者文件太大以至于无法放入字符串中,所以您想分段读取。
  • 等等..

更通用的解决方案是读取文件(因此,在 C++ 中,一个 fstream),使用函数 get 逐字节读取(参见http://www.cplusplus.com/reference/iostream/istream/get/),然后自己进行操作以将其转换为您期望的类型,并停在 EOF。

std::isteam 接口具有以不同方式读取文件所需的所有功能(请参阅http://www.cplusplus.com/reference/iostream/istream/),即便如此,std::string 还有一个额外的非成员函数来读取文件,直到找到一个分隔符(通常是“\n”,但它可以是任何东西,参见http://www.cplusplus.com/reference/string/getline/

但我想要 std::string 的“加载”函数!!!

好的,我明白了。

我们假设您放入文件中的是std::string 的内容,但保持它与C 风格的字符串兼容,即\0 字符标记字符串的结尾(如果不是,我们需要加载文件直到到达 EOF)。

我们假设您希望在函数 loadFile 返回后完全加载整个文件内容。

所以,这里是loadFile 函数:

#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 ;
}

如果您使用的是启用 C++11 的编译器,您可以添加这个重载函数,这将花费您nothing(而在 C++03 中,通过优化,它可以 花了你一个临时对象):

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

现在,为了完整起见,我编写了相应的saveFile 函数:

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 ;
}

这里是我用来测试这些功能的“主要”:

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" ;
    }
}

更多?

如果您想做更多的事情,那么您需要探索 C++ IOStreams 库 API,地址为 http://www.cplusplus.com/reference/iostream/

【讨论】:

    【解决方案2】:

    您不能使用std::istream::read() 读入std::string 对象。您可以做的是确定文件的大小,创建一个合适大小的字符串,并将数据读入字符串的字符数组:

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

    棘手的一点是确定字符串应具有的大小。鉴于字符序列可能在读取时被翻译,例如,因为行尾序列被转换,这几乎相当于在一般情况下读取字符串。因此,我建议不要这样做。相反,我会使用这样的方式读取字符串:

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

    这适用于文本字符串,并且在大多数系统上运行速度差不多。如果文件可以包含空字符,例如,因为它包含二进制数据,那么这并不完全有效。如果是这种情况,我会使用中间的std::ostringstream

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

    【讨论】:

    • 天哪,这看起来不像我希望的那么简单。不过,感谢您的回答。我希望我能接受它并让它发挥作用。
    • 我强烈推荐使用第二种方法。第一种方法更复杂,第二种方法应该可以正常工作。
    【解决方案3】:

    字符串对象不仅仅是一个字符数组,行

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

    可能是你问题的根源。

    尝试应用以下更改:

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

    【讨论】:

      猜你喜欢
      • 2014-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-04
      相关资源
      最近更新 更多