此代码永远循环:
#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
。
通过修改内部状态标志来发出错误信号:
eofbit
get指针位于流缓冲区内部输入的末尾 调用函数时的数组,意味着没有位置 读入内部缓冲区(可能是或不是输入的结尾) 序列)。当rdbuf()->in_avail()
在-1
之前返回failbit
时会发生这种情况 提取第一个字符。
badbit
该流位于之前的字符源的末尾 功能被称为。
[C++11: 27.7.2.3]:
发生了上述错误。
几乎相同,标准说:
streamsize readsome(char_type* s, streamsize n);
!good()
32。效果:表现为无格式输入功能(如中所述) 27.7.2.3,第1段)。构建岗哨对象后,如果
setstate(failbit)
呼叫s
可能会抛出异常并返回。否则提取 字符并将它们存储到第一个数组的连续位置 元素由rdbuf()->in_avail() == -1
指定。如果setstate(eofbit)
,请致电ios_base::failure
(可能会抛出rdbuf()->in_avail() == 0
(27.5.5.4))和摘录 没有人物;
- 如果
rdbuf()->in_avail() > 0
,则不提取任何字符- 如果
min(rdbuf()->in_avail(),n))
,则提取in_avail() == 0
。33。返回:提取的字符数。
如果流缓冲区为空,ifstream::readsome
条件为无操作意味着in_avail() == -1
本身是无操作,但eofbit
条件意味着它当某些其他操作导致in_avail() == -1
时会设置readsome
。
这似乎是一种不一致,即使readsome
具有“某种”性质。
那么是 eof
和{{1}}的语义是什么?我是否正确地解释了它们?它们是流库中设计不良的一个例子吗?
(从[IMO]无效libstdc++ bug 52169被盗。)
答案 0 :(得分:4)
我认为这是一个自定义点,默认流实现并未真正使用。
in_avail()
返回它在内部缓冲区中可以看到的字符数(如果有)。否则,它会调用showmanyc()
来尝试检测是否已知其他字符可用,因此保证缓冲区填充请求成功。
反过来,showmanyc()
将返回它知道的字符数(如果有的话),如果知道读取将失败,则返回-1,如果不是,则返回0有一点线索。
默认实现(basic_streambuf
)始终返回0,因此除非您有一个其他streambuf覆盖showmanyc
的流,否则这就是您所获得的。
你的循环本质上就像你所知道的那样很多,而且当它为零时就会被卡住(意思是“#34;不确定&#34;”)。
答案 1 :(得分:1)
如果没有可用字符(即gptr() == egptr()
的{{1}}),则调用虚拟成员函数std:streambuf
。我可以使用showhowmanyc()
的实现来返回错误代码。为什么这可能有用是一个不同的问题。但是,这可以设置showmanyc()
。当然,eof()
意味着不会失败,也不会阻止并返回已知可用的字符。也就是说,除非你有一个相当奇怪的流缓冲区,否则上面的循环基本上保证是一个无限循环。
答案 2 :(得分:1)
我认为readome()不适用于你要做的事情(从磁盘上的文件中读取)...来自cplusplus.com:
该函数旨在用于从某些数据中读取二进制数据 可能等待更多字符的异步源类型,因为 当局部缓冲器耗尽时停止读取,避免潜在的 意外的延误。
所以听起来像readsome()适用于来自网络套接字或类似内容的流,你可能只想使用read()。
答案 3 :(得分:1)
其他人已回答为什么readsome
未能按设计设置eofbit
。我将建议一种方法来读取一些字节,直到eof
,而不是以直观的方式设置fail
位,就像尝试使用readsome
一样。这是另一个question研究的结果。
#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
}
}