4

在下面的代码片段中,有没有办法处理ENOSPC

#include <fstream>
#include <iostream>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/bzip2.hpp>

// open input file stream of the bzip2 file
std::ifstream ifs("file.bz2");

// open output stream to the "full" device
// full device is a "utility-device" to check how applications handle ENOSPC
// more details in "man full"
std::ofstream ofs("/dev/full");

// Setup the iostreams filter
boost::iostreams::filtering_streambuf<boost::iostreams::output> filters;
filters.push(boost::iostreams::bzip2_decompressor());
filters.push(ofs);

// "run" the filter
boost::iostreams::copy(ifs, filters);

如果我strace使用已编译的二进制文件,代码似乎会无限调用writev()相同的数据并返回ENOSPC错误。

writev(4, [{NULL, 0}, {"DATA DATA "..., 4096}], 2) = -1 ENOSPC (No space left on device)

如何处理此错误或将其作为错误从boost::iostreams::copy().

exceptions()是否可以在对象上设置适当的ofstream?我试过ofs.exceptions(std::ios::badbit | std::ios::failbit)了,但没有任何区别。

上面的代码使用 GCC 编译并在 Linux 上运行。提升版本 1.55。

4

2 回答 2

4

它陷入了无限循环non_blocking_adaptor<Device>::write(...)

std::streamsize result = 0;
while (result < n) {
    std::streamsize amt = 
        iostreams::write(device_, s + result, n - result);
    result += amt;
}
return result;    

iostream::write(device_, ...不断返回 0(所以 n 保持 n,amt 和结果保持 0)。


这似乎是 Boost IOstreams 中的一个错误。可能是在添加对非阻塞(同步)IO 的初步支持时引入的。根据文档,这应该是一项正在进行的工作。

特别有启发性的是:http: //www.boost.org/doc/libs/1_55_0/libs/iostreams/doc/guide/asynchronous.html

过滤器

允许过滤器传播临时故障通知:如果下游设备消耗或产生的字符少于过滤器请求的字符,并且因此过滤器无法满足读取或写入请求,则过滤器可能会返回一个值,指示输入或输出暂时不可用。希望这种能力足以允许当前的过滤器概念与异步和非阻塞 i/o 一起使用。然而,为了对阻塞 i/o 也有用,过滤器绝不能返回临时故障通知,除非它已从下游 Device 收到此类通知。通过声明过滤器必须保留阻塞来总结此要求。请参阅阻止。

粗体字) IOStreams 似乎违反了这一原则,将 E_NOSPC 条件转换为临时故障通知


boost::iostreams::copy源和目标间接设备的特殊情况。在这种情况下,两者都是间接的。现在,特殊情况将水槽包裹在non_blocking_adaptor. 我不知道为什么,这似乎与从同一文档页面获取的以下一般建议相矛盾:

流和流缓冲区

尽管 Boost.Iostreams 过滤器和设备概念可以适应非阻塞 i/o,但 C++ 标准库流和流缓冲区接口不能,因为它们缺乏区分临时和永久故障以满足读取或写入请求的方法。因此,非阻塞设备无法与模板流、stream_buffer、filtering_stream 和 filtering_streambuf 一起正常工作。

我试图用file_sinkand替换文件file_source,但没有任何变化。:(

这是我简化的测试用例,它仍然重现了这个问题:

#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>

int main()
{
    using namespace boost::iostreams;
    file_source ifs("/dev/zero");
    file_sink   ofs("/dev/full");

    filtering_streambuf<output> filters(ofs);
    copy(ifs, filters);
}

也许您应该将其报告为开发人员/邮件列表的错误。

于 2013-12-07T03:03:09.480 回答
2

我想我已经找到了解决这个问题的方法。我所做的是根据此处的文档制作自己的水槽。

基本上是sink处理写入然后检查流的good状态。

struct safe_ofstream_sink
{
    typedef char char_type;
    typedef boost::iostreams::sink_tag category;

    std::ofstream& ofs;

    safe_ofstream_sink(std::ofstream& ofs) :
            ofs(ofs)
    {
    }

    std::streamsize write(const char* s, std::streamsize n)
    {
        ofs.write(s, n);
        if (!ofs)
            throw std::runtime_error("Failed writing to fstream");

        return n;
    }
};


boost::iostreams::filtering_streambuf<boost::iostreams::output> filters;
filters.push(boost::iostreams::bzip2_decompressor());
filters.push(safe_ofstream_sink(ofs));
boost::iostreams::copy(ifs, filters);
于 2013-12-09T13:15:57.077 回答