WEBVTT

00:00.420 --> 00:04.110
Hello again! In this video, we are going to look at random access to streams.

00:04.650 --> 00:09.720
Normally when we access a stream, we do it sequentially. So we start at the beginning and go through

00:09.720 --> 00:12.300
it step by step until we get to the end.

00:12.690 --> 00:13.380
And then we stop.

00:14.430 --> 00:19.350
But it is possible to access streams randomly, which means we can jump to any position we want.

00:19.650 --> 00:22.230
And read or write data from that position.

00:26.240 --> 00:31.760
The stream classes in C++ have a data member, which keeps track of where the last operation stopped.

00:32.210 --> 00:37.490
That is known as the position marker. If you have performed a write operation,

00:37.550 --> 00:39.140
this will be at the end of the stream.

00:39.140 --> 00:42.080
So just after the data that you've written to the stream.

00:42.890 --> 00:47.000
If you did a read operation, this will be pointing to the following data.

00:47.390 --> 00:52.160
So that is the start of the data that will be retrieved by the next read operation.

00:53.030 --> 00:54.830
And normally that is controlled by the stream.

00:57.670 --> 01:03.370
There are some cases where the programmer can set the position of this marker. If you have a file stream

01:03.370 --> 01:09.460
and it was not opened in append mode, or if you have a string stream. In that case, you can set the position

01:09.460 --> 01:14.950
of the marker. And you can use that to read or write data, anywhere in the stream, because that controls

01:14.950 --> 01:16.960
where the next operation will take place.

01:21.470 --> 01:27.020
The streams have member functions. The seek member functions will change the position of the marker.

01:28.070 --> 01:30.290
They have different names for different streams.

01:30.740 --> 01:35.930
This is because they come from C, which doesn't have the notion of overloaded functions or indeed

01:36.170 --> 01:36.740
functions.

01:37.730 --> 01:41.450
If you have an input stream, then seekg() will set the current position.

01:41.930 --> 01:44.000
So it's 'g' for a "get" operation.

01:44.450 --> 01:50.600
If you have an output stream, then seekp() will set the current position, so that's for a "put" operation.

01:53.790 --> 01:59.340
And there are also member functions which will give you the current position of the marker. tellg()

01:59.340 --> 02:04.590
will give you the position for an input stream and tellp() will give its for an output stream.

02:11.470 --> 02:17.770
These operations are only defined where they make sense, so seekg() and tellg() are only defined for input

02:17.770 --> 02:21.940
streams and seekp() and tellp() are are only defined for output streams.

02:22.840 --> 02:26.170
They are defined for iostreams, but they do not do anything useful.

02:26.770 --> 02:30.130
They give you a runtime error and they put the stream into an invalid state.

02:30.580 --> 02:31.390
So do not do that!

02:33.080 --> 02:40.010
If you have an fstream and it is opened in append mode, then seekp() does nothing. The stream will always write

02:40.040 --> 02:41.690
the output at the end of the file.

02:45.530 --> 02:51.470
The return value from tell is an object of type "pos_type", and this represents a

02:51.470 --> 02:52.450
position in the stream.

02:54.410 --> 03:01.070
It can be converted to an int, so you can print it out or compare it against an int. If the stream is

03:01.070 --> 03:03.500
in an invalid state when you call the tell operation,

03:03.980 --> 03:09.260
this operation will fail, and you can find that by comparing the return value to minus one.

03:10.220 --> 03:15.950
So if you do a tell and the return value is not minus one, then the operation succeeded ,and you have

03:15.950 --> 03:17.330
a valid position marker.

03:22.300 --> 03:27.880
You can pass this result to a seek operation, so you can seek to a particular position.

03:31.080 --> 03:32.520
And that is an absolute position.

03:32.910 --> 03:35.250
You can also seek to a relative position.

03:35.460 --> 03:40.620
So, so many bytes from the beginning or end of the stream, or so many bytes from the current position.

03:41.310 --> 03:48.000
So for example, you can say that's the base position is the end, ios_base::end, and you want to move

03:48.000 --> 03:49.320
minus 10 bytes from that.

03:49.740 --> 03:52.500
So that means 10 bytes before the end of the stream.

03:57.900 --> 04:02.400
One thing you can do is to save the current position of the marker, so you can get it later.

04:02.820 --> 04:09.270
So that is a bit like putting a bookmark in your file or your stream. So you could open some output stream

04:09.270 --> 04:14.400
and send some data to it, and then you save the position of the marker.

04:14.400 --> 04:16.530
So that is where the stream currently is.

04:18.930 --> 04:24.270
And then you can write some more data to the stream. And if you later decide that you want to go back and

04:24.690 --> 04:29.520
undo that output, or overwrite it, then you can seek to the position.

04:29.760 --> 04:33.180
So this is the bookmark and this will return to the bookmark.

04:33.810 --> 04:37.500
And then if you write again, this will overwrite all the data that you put here.

04:38.010 --> 04:39.690
So here is an example.

04:40.470 --> 04:43.140
We open an output, an ostringstream.

04:44.400 --> 04:51.000
We have some data we are going to send to it. And then we call tellp() to get the position marker for

04:51.000 --> 04:51.930
the stringstream.

04:54.580 --> 04:59.260
Then we compare the position of the marker and the number of characters we have written to the stream.

05:00.850 --> 05:04.600
And then with the stream at that position, we then write "hello".

05:05.200 --> 05:09.480
So that is going to make the marker move forward five bytes; five bytes for "hello".

05:10.300 --> 05:12.370
And then we can check the new value of the marker.

05:14.440 --> 05:20.110
Then we print out all the data in the string. And then we go back to the position marker that we saved

05:20.110 --> 05:20.440
earlier.

05:20.860 --> 05:21.970
So that is before

05:21.970 --> 05:22.420
"hello".

05:23.410 --> 05:26.380
And then we put "goodnight" on the stream.

05:26.800 --> 05:29.170
So this is going to overwrite "hello" with "goodnight".

05:29.920 --> 05:30.940
So let's see what happens.

05:36.450 --> 05:41.970
So we wrote 18 characters to the stream, so "It is time to say" has 18 characters.

05:42.630 --> 05:49.200
The stream marker is 18 bytes into the stream. So 'I' goes at byte 0, 't' goes at byte one and so on, and the

05:49.200 --> 05:51.260
last character went at byte 17.

05:51.900 --> 05:54.750
So the next operation will be at byte number 18.

05:55.920 --> 05:59.900
Then we send another five bytes to the stream, so the marker moves ahead five bytes.

05:59.910 --> 06:05.160
It is now at position number 23, and we have a string which says "It is time to say hello".

06:06.980 --> 06:13.340
Then we go back to the position before we wrote "hello", and we write, "goodnight", so we have

06:13.340 --> 06:13.730
overwritten

06:13.730 --> 06:14.900
"hello" with "goodnight".

06:17.230 --> 06:21.010
So you could use this with a file stream to modify a file in place.

06:22.450 --> 06:25.900
However, the best way to modify a file is actually to read it into memory.

06:26.170 --> 06:31.450
Make your changes in memory and then write them over the original file. So you could, for example,

06:31.510 --> 06:33.580
read the data into an istringstream.

06:34.390 --> 06:40.720
Then you get the bound string, and make the changes to the data, in the string, and then you write that

06:40.720 --> 06:42.880
string over the original file.

06:46.300 --> 06:49.390
If you use seek and tell, this will modify the file in place.

06:50.200 --> 06:54.800
It is more complicated, it is harder to get right and if you do make a mistake, then you have overwritten

06:54.820 --> 06:58.900
the data, so the original file is no longer available. Unless you made a back up.

07:00.430 --> 07:04.840
This could be useful, though, if you have a very large file, or a very limited amount of memory, and

07:04.840 --> 07:08.200
you cannot read the entire contents of the file into memory in one go.

07:10.970 --> 07:15.290
Okay, so that is it for this video, it is time for me to say goodnight. Or rather, good afternoon!

07:15.920 --> 07:16.790
I will see you next time.

07:17.090 --> 07:18.770
Meanwhile, keep coding!
