为什么std :: copy(从istream到ostream)会引发ios :: failure异常?

时间:2010-11-04 17:25:46

标签: c++ stl stream

以下代码应将数据从wifstream复制到wcout。 复制内容后,程序将抛出ios :: failure异常。

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


int main(void)
{
    std::locale::global(std::locale(""));

    std::wifstream is;
    is.exceptions( std::ios::failbit | std::ios::badbit );
    is.open("test.ts", std::ios::binary);

    is >> std::noskipws;

    std::istream_iterator<wchar_t, wchar_t> in(is);
    std::istream_iterator<wchar_t, wchar_t> end;

    std::copy(in, end,
              std::ostream_iterator<wchar_t, wchar_t>(std::wcout));

    return 0;
} 

如果出现任何问题,流应该只抛出异常(参见异常掩码),但不会抛出EOF。

3 个答案:

答案 0 :(得分:1)

为避免跳过空格,请使用std :: istreambuf_iterator

std::copy(std::istreambuf_iterator<wchar_t, wchar_t>(is),
          std::istreambuf_iterator<wchar_t, wchar_t>(),
          std::ostream_iterator<wchar_t, wchar_t>(std::wcout));

例外:

本地可能正在使用失败的codecvt方面 尝试注释区域设置行,看看会发生什么。

您是否尝试打印例外情况?

try
{
    // do work
}
catch(std::exception const& e)
{
    std::cout << e.what() << "\n";
}

答案 1 :(得分:1)

因为你正在使用std::istream_iterator,所以尝试读取流末尾的字符会同时设置eofbitfailbit(并且只有在设置了一些错误位之后,才会迭代器变得等于结束迭代器)

剥离必需品并恢复为char以使其更简单,程序相当于:

#include <iostream>
#include <fstream>
int main()
{
    std::ifstream is("test.txt", std::ios::binary);
    is.exceptions(std::ios::failbit); // failbit only because that's what you get
    is >> std::noskipws;
    if(is)
        for(char c; is >> c;) // will throw!
            std::cout << c;
}

答案 2 :(得分:0)

根据§27.6.1.2.3/ 10:

  

构建sentry对象后,将从 中提取一个字符(如果有),并存储在 c 中。否则,该函数调用 in.setstate(failbit)

因此,当它到达文件末尾并且无法再提取字符时,它将设置失败位,您已将其设置为产生异常。使用std::copy不会改变行为 - istream_iterator通过operator>>读取。

您可以更轻松地复制文件:

std::wifstream is("test.ts", std::ios::binary);
std::wcout << is.rdbuf();