【问题标题】:Reading and writing a std::vector into a file correctly with iterators使用迭代器正确读取和写入 std::vector 到文件中
【发布时间】:2016-04-08 17:58:34
【问题描述】:

我正在尝试理解here 提供的答案,但我似乎无法使其工作。

这是我尝试过的:

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

int main()
{
    std::string path("numbersfile");

    std::vector<int> myVector{1,16,32,64};
    std::vector<int> newVector{};

    std::ofstream FILE(path,std::ios::out | std::ofstream::binary);
    std::copy(myVector.begin(),myVector.end(),std::ostreambuf_iterator<char>(FILE));

    std::ifstream INFILE(path,std::ios::in | std::ifstream::binary);
    std::istreambuf_iterator<char> iter(INFILE);
    //std::copy(iter.begin(),iter.end(),std::back_inserter(newVector)); //this doesn't compile
    std::copy(iter,std::istreambuf_iterator<char>{},std::back_inserter(newVector)); // this leaves newVector empty
}

newVector 在最后一个 copy 之后仍然为空。如何更新最后一条语句以填充 newVector

【问题讨论】:

  • FILE.flush(); 就在第一个 std::copy 之后?

标签: c++ c++11


【解决方案1】:

在调用第二个copy 时,该文件尚未准备好读取。 (感谢 Piotr Skotnicki 在 cmets 中的回答)

调用flush 允许程序运行:

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

int main()
{
    std::string path("numbersfile");

    std::vector<int> myVector{1,16,32,64};
    std::vector<int> newVector{};

    std::ofstream FILE(path,std::ios::out | std::ofstream::binary);
    std::copy(myVector.begin(),myVector.end(),std::ostreambuf_iterator<char>(FILE));
    FILE.flush(); // required here

    std::ifstream INFILE(path,std::ios::in | std::ifstream::binary);
    std::istreambuf_iterator<char> iter(INFILE);
    //std::copy(iter.begin(),iter.end(),std::back_inserter(newVector)); //this doesn't compile
    std::copy(iter,std::istreambuf_iterator<char>{},std::back_inserter(newVector)); // this leaves newVector empty
    return 0;
}

ofstream 在创建 ifstream 时仍在范围内。如果调用了ofstream 的析构函数,那么该文件也已准备好用于ifstream。在以下程序中,ifstream 会自动销毁:

#include <algorithm>
#include <fstream>
#include <iterator>
#include <vector>

std::string filename("numbersfile");

std::vector<double> myVector{1.342, 16.33, 32.1, 12364};

void write_vector_to_file(const std::vector<double>& myVector, std::string filename);
std::vector<double> read_vector_from_file(std::string filename);

int main()
{
    write_vector_to_file(myVector, filename);
    auto newVector{read_vector_from_file(filename)};
    return 0;
}

void write_vector_to_file(const std::vector<double>& myVector, std::string filename)
{
    std::ofstream ofs(filename, std::ios::out | std::ofstream::binary);
    std::ostream_iterator<double> osi{ofs," "};
    std::copy(myVector.begin(), myVector.end(), osi);
}

std::vector<double> read_vector_from_file(std::string filename)
{
    std::vector<double> newVector{};
    std::ifstream ifs(filename, std::ios::in | std::ifstream::binary);
    std::istream_iterator<double> iter{ifs};
    std::istream_iterator<double> end{};
    std::copy(iter, end, std::back_inserter(newVector));
    return newVector;
}

【讨论】:

  • 如果我们要读/写的向量不是char类型而是double怎么办?
  • @rivaldo4t 好问题。 :) 我已经更新了要显示的最后一个程序。看来我应该为std::ostream_iterator 提供一个分隔符,并使用istream_iterator 来读取文件。
【解决方案2】:

您的代码中有许多缺陷:

  1. 你定义了一个名为FILE的变量这很糟糕,很糟糕FILE 是一个已经存在的对象的名称,它类似于将 vector 的实例命名为:std::vector&lt;int&gt;array{}
    它不仅令人困惑而且非常危险,因为它几乎肯定会导致命名冲突。另外,所有的首都名称都应该为宏保留

  2. 您永远不会检查文件是否实际打开,如果不是,编译器不会警告您并且流不会给出任何失败指示(除非明确检查)。所以,你应该经常检查。最简单的方法也是使用流布尔运算符:
    if (!ifile) throw std::runtime_error("error opening file");

  3. 你写道这不会编译:

    std::copy(iter.begin(),iter.end(),std::back_inserter(newVector));

    为什么会这样?迭代器本身没有beginend 函数,与迭代器关联的对象有这些方法。

  4. 将所有这些拼凑在一起是您的代码的修改版本:

    {
        std::string path("numbersfile");
    
        std::vector<int> myVector{ 1,16,32,64 };
        std::vector<int> newVector{};
    
    
        std::ofstream outfile(path, std::ios_base::binary);
        std::copy(myVector.begin(), myVector.end(), std::ostreambuf_iterator<char>(outfile));
    
        outfile.close(); 
    
        std::ifstream infile(path,std::ios_base::binary);
        std::istreambuf_iterator<char> iter(infile);
        std::copy(iter, std::istreambuf_iterator<char>(),    std::back_inserter(newVector)); // this leaves newVector empty
    
        infile.close(); // close explicilty for consistency 
    }
    

【讨论】:

  • 感谢您的评论。我从原始答案中得到了命名。这是可怕的。 :) 未编译的部分也来自accepted answer。建议在这种情况下明确使用close。我尝试添加您建议的throw(我同意良好的一般做法),但它没有解决这个问题,或者更确切地说,当我在 MSVC 上执行程序时它没有抛出。
  • throw 语句应该可以工作,确保包含 &lt;exception&gt; 标头。在每次打开后添加if-throw 语句。
  • 不,没用。也不起作用here
  • 如果它没有抛出则意味着文件打开正确,你确定它没有打开吗?没有理由它不应该工作,我测试了我事先给出的解决方案,它工作得很好。
  • 文件打开了,但是没有数据。
猜你喜欢
  • 2012-09-04
  • 1970-01-01
  • 2013-03-05
  • 1970-01-01
  • 1970-01-01
  • 2020-08-20
  • 2021-05-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多