【问题标题】:C++ fstream: how to know size of string when reading?C++ fstream:阅读时如何知道字符串的大小?
【发布时间】:2012-02-10 18:13:14
【问题描述】:

...有人可能还记得,我仍然停留在 C++ 字符串上。好的,我可以使用 fstream 将字符串写入文件,如下所示

outStream.write((char *) s.c_str(), s.size());

当我想读取那个字符串时,我可以这样做

inStream.read((char *) s.c_str(), s.size());

一切都按预期进行。问题是:如果我在将字符串写入文件并再次读取之前更改字符串的长度,打印该字符串不会让我恢复原始字符串,而是更短/更长的字符串。所以:如果我必须在一个文件中存储许多字符串,我如何在读取时知道它们的大小?

非常感谢!

【问题讨论】:

  • 确定首先要使用未格式化的 IO 吗?
  • 可能每行写一个字符串?

标签: c++ string fstream


【解决方案1】:

如果您只想编写普通的人类可读的字符串数据,则不应使用未格式化的 I/O 函数(read()write())。通常,您只在需要读取和写入紧凑的二进制数据时才使用这些函数,这对于初学者来说可能是不必要的。您可以改写普通的文本行:

std::string text = "This is some test data.";
{
    std::ofstream file("data.txt");
    file << text << '\n';
}

然后用getline()回复它们:

{
    std::ifstream file("data.txt");
    std::string line;
    std::getline(file, line);
    // line == text
}

您也可以使用常规格式化运算符&gt;&gt; 来读取,但是当应用于string 时,它会读取tokens(由空格分隔的非空白字符),而不是整行:

{
    std::ifstream file("data.txt");
    std::vector<std::string> words;
    std::string word;
    while (file >> word) {
        words.push_back(word);
    }
    // words == {"This", "is", "some", "test", "data."}
}

所有格式化的 I/O 函数都会自动为您处理内存管理,因此无需担心字符串的长度。

【讨论】:

  • 太棒了,我不知道如何感谢你!我还有一个小问题:如果我的函数得到一个字符串,有没有办法知道该字符串是否已经用换行符终止?
  • @user732274 :使用格式化的 IO,您将永远将换行符读入字符串(除非您将非默认分隔符传递给 std::getline)。
【解决方案2】:

虽然你的写作解决方案或多或少可以接受,但你的阅读解决方案存在根本缺陷:它使用旧字符串的内部存储作为新字符串的字符缓冲区,这非常非常不好(委婉地说)。

您应该切换到一种格式化的方式来读取和写入流,如下所示:

写作:

outStream << s;

阅读:

inStream >> s;

这样你就不需要费心去确定你的字符串的长度了。

这段代码的不同之处在于它在空白字符处停止;如果您只想停在\n 个字符处,可以使用getline

【讨论】:

    【解决方案3】:

    您可以写入字符串并将附加的 0(空终止符)写入文件。这样以后就可以很容易地分离字符串了。此外,您可能想要读取和写入行

    outfile << string1 << endl;
    getline(infile, string2, '\n');
    

    【讨论】:

      【解决方案4】:

      如果您想使用未格式化的 I/O,您唯一真正的选择是使用固定大小或以某种方式预先设置大小,以便您知道要读取多少个字符。否则,在使用格式化 I/O 时,它在某种程度上取决于您的字符串包含的内容:如果它们可以包含所有可行的字符,您将需要实现某种引用机制。在简单的情况下,字符串由例如对于无空间序列,您可以只使用格式化 I/O 并确保在每个字符串后写一个空格。如果您的字符串不包含某些可用作引号的字符,则处理引号相对容易:

      std::istream& quote(std::istream& out) {
          char c;
          if (in >> c && c != '"') {
              in.setstate(std::ios_base::failbit;
          }
      }
      
      out << '"' << string << "'";
      std::getline(in  >> std::ws >> quote, string, '"');
      

      显然,您可能希望将此功能捆绑到一个类中。

      【讨论】:

        猜你喜欢
        • 2015-03-15
        • 1970-01-01
        • 2012-02-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多