10

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.

FlintZA
  • 812
  • 1
  • 12
  • 21
  • 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. – FlintZA Oct 29 '09 at 09:18
  • 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... – Alexis Wilke Mar 11 '17 at 02:28

4 Answers4

10

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
Éric Malenfant
  • 13,450
  • 1
  • 36
  • 41
  • 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. – FlintZA Oct 29 '09 at 09:19
  • It looks like the return type from tellg() is always numeric, based on a [constraint of std::streampos](http://stackoverflow.com/a/24437482/145173). – Edward Brey Sep 19 '15 at 16:21
-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.

Morix Dev
  • 2,592
  • 24
  • 47
  • 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... – Monza Apr 12 '21 at 02:21
-2

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

Marcin
  • 11,616
  • 9
  • 39
  • 47
  • 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). – FlintZA Oct 29 '09 at 10:21
-2

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).

Soleil
  • 4,891
  • 3
  • 27
  • 47