理解std::istream::read的设计

5

std::istream 的原型是 istream& read (char* s, streamsize n),实际读取的字节数可以通过调用 istream::gcount() 来获取,同时可以从 ios::good 中了解 istream 的有效性。

我正在与同事讨论另一个流类的实现,我想写的时候可能会遵循这个设计;但他说,不必每次都调用 gcount,可以将 read 的原型设置为 istream& read (char* s, streamsize n, size_t &bytes_read),这样就可以在一次调用中完成,前者比较笨拙。我无法为 std 的设计选择进行辩护。什么是 istream::read 的真正原理?


你是指 size_t& bytes_written 吗?而且,它可能应该是 streamsize& bytes_written(或者也许是 chars_read)。 - James McNellis
@James:是的,谢谢!在这里,字节和字符是同义词,因为 sizeof 是相同的 :) - legends2k
4个回答

4
我猜这是因为C++通常不会强制要求每个人都需要的接口。如果您需要read接受某些人不关心的参数,则会导致额外的编程工作(声明一个额外的int作为参数传递)。无论客户端是否关心,它也总是保存读取的字节(有些客户端可能只关心读取失败,如eof/fail位所示)。
使用单独的方法可以将可能或可能不需要的不同信息的接口解耦。

3
尝试使用readsome命令代替。
streamsize readsome ( char* buf, streamsize num );

buf是您的缓冲区,num是您希望读取的字节数,最多不超过缓冲区中可用的字节数。

返回值是实际读取的字节数。

要读取文件直到结束,可以使用循环:

char buf[BUF_SIZE]
streamsize bytesRead;
do
{
   bytesRead = instr.readsome( buf, BUF_SIZE );
   // do stuff with the bytes you read, if any
} while ( bytesRead == BUF_SIZE );

0

std::istream 的原型为 istream& read (char* s, streamsize n) 实际读取的字节数应该通过调用istream::gcount()来获得,同时可以从ios::good中了解istream的有效性。

istream::read(char* s, streamsize n)读取一个大小为n的未格式化的数据块(没有NULL终止符)到位于s的数组中。尽管s是指向char的指针,但您可以使用istream::read读取二进制数据。例如,您可以有一个包含双精度数组值的istream(假设字节序正确):

unsigned int count;
input.read(reinterpret_cast<char*>(&count), sizeof(count));
double* data = new double[count];

for (unsigned int i = 0; i < count; ++i)
    input.read(reinterpret_cast<char*>(data[i]), sizeof(double));

istream::gcount() 返回上一次 istream::read 调用中读取的字节数。在这种情况下,我们可以看到 count 的大小可能与 double 的大小不同,因此我们将无法使用 istream::gcount() 来指定 data 数组中第一个元素的大小。


@CashCow 对于 istream::read 的限制有正确的解决方案。我不能点赞,因为我没有至少 15 分的声望(我还是一个 Stack Overflow 新手)。 - Jaime Soto
我的实际问题是,为什么我们需要调用gcount;而不是让调用者传递一个引用变量,该变量将由read设置为实际读取的字节数(可能小于或等于streamsize n),而不是每次调用者都要调用gcount。 - legends2k
正如@CashCow所解释的那样,使用istream::readsome返回读取的字节数似乎更可取。正如@Mark B所解释的那样,这避免了声明额外的int来传递引用。另一个选择是传递指向变量的指针,默认为NULL,可以用于忽略实际读取的字节数:istream&read(char * s,streamsize n,streamsize * bytesRead = NULL)。但是,我不知道它是否比istream::readsome提供了显着的优势。 - Jaime Soto

0
作为对原问题的回应,在C语言年轻时,具有错误检查调用是一种流行的编程风格,但很快就过时了。发生的事情是,存在一些微不足道的小事情,虽然并不是非常严重,但几乎总是存在一些稍微劣质的东西,直到它们被社区指出并标记为不好为止。这段代码不幸的是在那个小反模式被广泛讨论之前就已经被编写了。
针对Cash Cow的解决方案,我认为存在一个错误。如果你正在等待IO并且有足够的字符部分填充缓冲区,那么函数将返回并且while循环将在文件完全读取之前结束。因此,他的解决方案可能会在直接使用原始IO时正确运行,但在使用缓冲IO时会失败。
当然,正确的解决方案是在EOF标志设置时结束while循环。目前我不确定badbit设置时最佳响应是什么,但你也应该处理这种情况。
我同意readsome是read的一个不错的替代品。
编辑: 有时readsome不可用(某些VC++版本)。在这种情况下,read是可以使用的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接