Better way to determine length of a std::istream?
Asked Answered
H

4

14

Is there a better way to determine the length of an std::istream than the following:

std::istream* pcStream = GetSomeStream();
pcStream->seekg(0, ios::end);
unsigned int uiLength = pcStream->tellg();

It just seems really wasteful to have to seek to the end of the stream and then seek back to the original position, especially if the stream might be to a file on some slow media like a CD or DVD.

Hydromedusa answered 27/10, 2009 at 14:42 Comment(2)
An API I'm using requires the size of the data I'm passing it. It uses a raw character buffer, and keeps processing it until it reaches the end of the buffer.Hydromedusa
You could use a stat() on the file. However, it is not any faster than seeking at the end and seeking back at the beginning before reading the contents... that's how file descriptors are implemented. Of course, stat() is not C++ and it requires a filename...Mandragora
C
12

The "best" way is to avoid needing the length :)

  • Not all streams are seekable (For example, imagine an istream on a network socket)
  • The return type from tellg() is not necessarily numeric (the only requirement is that it can be passed back to seekg() to return to the same position)
  • Even if it is numeric, it is not necessarily a number of bytes. For example, it could be a "magic" value meaning "at the end"
  • For fstreams, issues like case and linefeed conversion can screw things up
Cattima answered 27/10, 2009 at 15:0 Comment(2)
I do realize expecting a length to always be available is a bit limiting to the kind of streams to be used, thankfully it's very unlikely I'll be using anything other then ifstreams and my own memstream and zipstream implementations.Hydromedusa
It looks like the return type from tellg() is always numeric, based on a constraint of std::streampos.Feudality
S
-1

Have you considered keeping track of the size by using istream::gcount() ?

Smail answered 27/10, 2009 at 15:0 Comment(1)
I require the size for allocation of the buffer to which the data will be copied-I suppose I could allocate an initial amount and realloc thereafter, but I'm a bit worried about fragmentation (working in a limited mem environment).Hydromedusa
D
-1

There was some kind of stream which couldn't get length by calling tellg(). In case of, tellg() may return -1.

You could get stream length by preparing enough sized buffer. I found out how to get length by looking into stream::read function.

const int DATA_SIZE = 1024 * 512;
char buf[DATA_SIZE];  // 1024 * 512 is enough!
std::istream& is = GetSomeStream();
int Len = is.rdbuf()->sgetn(buf, DATA_SIZE);

Above, Len is real data size in istream.

Durnan answered 7/7, 2015 at 5:42 Comment(2)
I'm going to add that this is useful if you're debugging. It's not ideal for production code etc but if you have a stream that won't obey logic you can peek into it's contents with this and determine what you're doing wrong...Bobstay
1024 * 512 is not portable when assigned to an int.Wavy
D
-1

In order to get the current length / size of a steam I do this:

auto size = strlen(currentStream.str().c_str());

This needs to happen before functions that will set its size to 0 such as move(currentStream).

Daye answered 4/1, 2019 at 22:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.