繁体   English   中英

什么时候`ifstream :: readsome`设置`eofbit`?

[英]When does `ifstream::readsome` set `eofbit`?

这段代码永远循环:

#include <iostream>
#include <fstream>
#include <sstream>

int main(int argc, char *argv[])
{
    std::ifstream f(argv[1]);
    std::ostringstream ostr;

    while(f && !f.eof())
    {
        char b[5000];
        std::size_t read = f.readsome(b, sizeof b);
        std::cerr << "Read: " << read << " bytes" << std::endl;
        ostr.write(b, read);
    }
}

这是因为readsome永远不会设置eofbit

cplusplus.com说:

通过修改内部状态标志来发出错误信号:

eofbit调用函数时,get指针位于流缓冲区内部输入数组的末尾,这意味着内部缓冲区中没有要读取的位置(可能是输入序列的末尾)。 rdbuf()->in_avail()在提取第一个字符之前返回-1时会发生这种情况。

failbit在调用函数之前,流位于字符源的末尾。

badbit上面发生的错误发生了。

几乎相同,标准说:

[C++11: 27.7.2.3]: streamsize readsome(char_type* s, streamsize n);

32.效果:表现为无格式输入函数(如27.7.2.3第1段所述)。 构造一个sentry对象之后,如果!good()调用setstate(failbit) ,它可能抛出一个异常,然后返回。 否则,提取字符并将它们存储到数组的连续位置,该数组的第一个元素由s指定。 如果rdbuf()->in_avail() == -1 ,则调用setstate(eofbit) (可能抛出ios_base::failure (27.5.5.4)),并且不提取任何字符;

  • 如果rdbuf()->in_avail() == 0 ,则不提取任何字符
  • 如果rdbuf()->in_avail() > 0 ,则提取min(rdbuf()->in_avail(),n))

33.返回:提取的字符数。

in_avail() == 0条件是无操作意味着如果流缓冲区为空, ifstream::readsome本身是无操作,但in_avail() == -1条件意味着它将设置eofbit 其他一些操作导致了in_avail() == -1

这似乎是一种不一致,即使尽管是readsome的“某种”性质。

那么,什么语义readsomeeof 我是否正确地解释了它们? 它们是流库中设计不佳的一个例子吗?


(从[IMO]无效的libstdc ++ bug 52169中窃取 。)

我认为这是一个自定义点,默认流实现并没有真正使用它。

in_avail()返回它在内部缓冲区中可以看到的字符数(如果有的话)。 否则,它会调用showmanyc()来尝试检测是否已知其他字符可用,因此保证缓冲区填充请求成功。

反过来, showmanyc()将返回它知道的字符数(如果有),如果它知道读取将失败则返回-1,如果它没有线索则返回0。

默认实现( basic_streambuf )总是返回0,所以这是你得到的,除非你有一个流与其他streambuf重写showmanyc

你的循环本质上就像你所知道的那样是多个字符,并且当它为零时(意味着“不确定”)它会被卡住。

其他人已回答为什么readsome不会设计eofbit 我将建议一种方法来读取一些字节,直到eof而不用直观的方式设置fail位,就像你尝试使用readsome 这是另一个问题研究的结果。

#include <iostream>
#include <fstream>
#include <sstream>

using namespace std;

streamsize Read(istream &stream, char *buffer, streamsize count)
{
    // This consistently fails on gcc (linux) 4.8.1 with failbit set on read
    // failure. This apparently never fails on VS2010 and VS2013 (Windows 7)
    streamsize reads = stream.rdbuf()->sgetn(buffer, count);

    // This rarely sets failbit on VS2010 and VS2013 (Windows 7) on read
    // failure of the previous sgetn()
    stream.rdstate();

    // On gcc (linux) 4.8.1 and VS2010/VS2013 (Windows 7) this consistently
    // sets eofbit when stream is EOF for the conseguences  of sgetn(). It
    // should also throw if exceptions are set, or return on the contrary,
    // and previous rdstate() restored a failbit on Windows. On Windows most
    // of the times it sets eofbit even on real read failure
    stream.peek();

    return reads;
}

int main(int argc, char *argv[])
{
    ifstream instream("filepath", ios_base::in | ios_base::binary);
    while (!instream.eof())
    {
        char buffer[0x4000];
        size_t read = Read(instream, buffer, sizeof(buffer));
        // Do something with buffer 
    }
}

如果没有可用的字符(即std:streambuf gptr() == egptr() showhowmanyc()则调用虚拟成员函数showhowmanyc() 我可以有一个showmanyc()的实现,它返回一个错误代码。 为什么这可能有用是一个不同的问题。 但是,这可以设置eof() 当然, in_avail()意味着不会失败,也不会阻止并只返回已知可用的字符。 也就是说,除非你有一个相当奇怪的流缓冲区,否则你上面的循环基本上保证是一个无限循环。

我不认为readome()是针对您尝试做的(从磁盘上的文件读取)...来自cplusplus.com:

该函数旨在用于从某些类型的异步源读取二进制数据,这些数据可能等待更多字符,因为它会在本地缓冲区耗尽时停止读取,从而避免潜在的意外延迟。

所以听起来像readsome()用于来自网络套接字或类似的流,你可能只想使用read()。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM