WEBVTT

0
00:00.810 --> 00:04.260
Hello again in this video, we're going look at file streams.

1
00:06.060 --> 00:08.880
We already know about input-output streams.

2
00:09.420 --> 00:14.040
cout and cin are objects of the ostream and istream classes.

3
00:15.300 --> 00:16.890
There is also fstream.

4
00:17.460 --> 00:25.200
So ofstream is a class for writing to files and ifstream is a class for reading from files.

5
00:26.660 --> 00:31.700
Unlike consoles, where there is only one console per computer, there can be many files.

6
00:32.090 --> 00:37.430
So when we use a file stream, we need to say which file we are going to use it with.

7
00:41.170 --> 00:47.230
The easiest way to do that is to pass the name of the file as the argument to the constructor of the

8
00:47.230 --> 00:47.980
file stream.

9
00:48.670 --> 00:56.970
So if we create an ifstream object for reading from a file, and we pass text dot txt as the argument, then

10
00:57.100 --> 01:01.360
the constructor of the file stream will open that file for reading.

11
01:02.020 --> 01:06.430
So that's going to set up the communication channel between the file and our program.

12
01:08.510 --> 01:14.300
The constructor will perform an open operation, which could fail; if the file does not exist or we are

13
01:14.300 --> 01:16.010
not allowed to read from it.

14
01:16.640 --> 01:21.170
So we need to check that we have a valid file stream object before we can use it.

15
01:22.190 --> 01:28.880
We can do that very easily, by putting the name of the object as a conditional. If the file stream is

16
01:28.880 --> 01:29.240
valid,

17
01:29.270 --> 01:34.130
this will be true. And then we can use the file stream to reach from the file.

18
01:35.030 --> 01:41.750
If the file stream is invalid, if the file could not be opened, then this would be false. And then

19
01:41.750 --> 01:44.360
we can go into an else branch which will handle the error.

20
01:48.450 --> 01:54.690
Incidentally, the in the version of C++ which introduced the standard string, they forgot to provide

21
01:54.690 --> 01:57.180
a constructor, which takes a standard string.

22
01:57.450 --> 02:03.270
But that has now been fixed. So you can now pass a string object as the argument to a file stream

23
02:03.270 --> 02:03.930
constructor.

24
02:07.710 --> 02:15.160
Reading from a file is the same as reading from standard input with cin. So we can just use the right

25
02:15.360 --> 02:18.000
shift operator, the double angle brackets.

26
02:19.130 --> 02:24.680
So this will cause the stream to fetch one value at a time from the file and put it in this variable.

27
02:26.150 --> 02:30.170
A value is defined as something that is separated by white space.

28
02:30.650 --> 02:37.190
So every time the stream encounters a space or tab or new line, it will decide that is the end of a

29
02:37.490 --> 02:41.810
value. And the next one starts after the end of the white space.

30
02:45.520 --> 02:49.030
And that can be problematic with keyboards, but more so with files.

31
02:49.610 --> 02:52.690
Often the space is actually part of the data that you want.

32
02:55.190 --> 03:00.500
Also, files often have some kind of structure. They have different fields which have a meaning.

33
03:01.550 --> 03:06.200
And in that case, your code has to match the structure of the file. And getting that right can

34
03:06.200 --> 03:07.220
be quite difficult.

35
03:08.430 --> 03:13.530
And also the question of error handling. If the structure of the file does not exactly match what you

36
03:13.530 --> 03:18.240
expect, perhaps the structure has changed or maybe you made a mistake?

37
03:18.660 --> 03:20.670
Or the file structure may have been corrupted.

38
03:22.050 --> 03:28.410
Let's have a look at using the right shift operator to read data from a file. So we are opening our

39
03:28.410 --> 03:32.160
file, text dot txt for input, to read from it.

40
03:33.060 --> 03:35.520
We check that the file was opened successfully.

41
03:36.300 --> 03:41.850
Then we have a string variable, which is going to hold the data from the file and then we read from

42
03:41.860 --> 03:45.630
it. One word at a time or one data field, if you like.

43
03:47.370 --> 03:51.990
And when there is no more data, this will return false and the loop terminates.

44
03:53.430 --> 03:58.110
We just print out each field as we get it, and then we close the file.

45
03:58.110 --> 04:02.430
So the close member function will cause the associated file to be closed.

46
04:03.990 --> 04:09.030
In that case, the stream object is no longer bound to the file, and it is just an empty stream object,

47
04:09.030 --> 04:10.590
which does not represent any file.

48
04:12.880 --> 04:16.480
So before we actually run this, we need to get a file to read from.

49
04:17.470 --> 04:23.260
In most IDE's, you can just take a file and drag it into the project directory and drop it.

50
04:24.380 --> 04:25.730
If you are using a command line,

51
04:26.950 --> 04:32.650
you could create the file in the directory where the program is going to run. With Visual Studio,

52
04:32.680 --> 04:37.750
you need to add it to the project, so you do Project, Add New Item.

53
04:39.850 --> 04:42.340
And then you have to find out where the text file is.

54
04:43.330 --> 04:48.610
I sometimes wonder if Microsoft has a special department that is responsible for moving things around,

55
04:48.610 --> 04:53.740
so no-one can find them! In this version of Visual Studio, it is in Utility.

56
04:54.190 --> 04:55.720
And then there is Text File.

57
04:56.980 --> 05:00.880
So let's make that lowercase, so it matches the slide.

58
05:03.440 --> 05:05.600
And then we can paste some data into that.

59
05:06.380 --> 05:06.800
There we go.

60
05:08.510 --> 05:10.310
If we look at the Solution Explorer,

61
05:13.660 --> 05:17.440
then we see that we now have this text.txt as part of the project.

62
05:18.100 --> 05:20.980
So this will actually be in the same directory that the program runs in.

63
05:22.850 --> 05:24.710
And now we can run it.

64
05:27.790 --> 05:33.700
So there we are. It has fetched the data from the file, one word at a time, and it has printed them out

65
05:34.030 --> 05:35.410
with commas between them.

66
05:40.900 --> 05:44.830
So as we said, there can be some issues with using the right shift operator.

67
05:45.880 --> 05:49.090
The best way to read input is to use the getline function.

68
05:49.720 --> 05:55.030
So this will take the stream to read from as the first argument, and a string object as the second

69
05:55.030 --> 05:55.510
argument.

70
05:56.140 --> 06:00.490
And then it will read a line, from the file, into this string object.

71
06:01.390 --> 06:04.000
If there is a new line character, it will regard

72
06:04.000 --> 06:09.490
that as the end of the line. So it will stop. And it will actually remove that newline character from the

73
06:09.490 --> 06:09.910
data.

74
06:10.390 --> 06:17.290
So this string object will contain the entire line of the text, except for the new line character.

75
06:18.800 --> 06:24.800
getline will return true when it reads a line of text. It will return false when it gets to the end

76
06:24.800 --> 06:31.970
of the file. So you can put this inside a loop and it will keep looping as long as it reads text,

77
06:32.090 --> 06:37.400
and then you can process the text inside the loop body. When it gets to the end of the file,

78
06:37.670 --> 06:39.140
the loop will terminate.

79
06:42.880 --> 06:49.270
So the advantage of this is that you have the data in a string object and then you can process it as

80
06:49.270 --> 06:49.660
you want.

81
06:51.790 --> 06:56.770
So here is the same file again. But this time we are going to use getline to get the data from it.

82
07:00.680 --> 07:01.550
So there we are.

83
07:01.670 --> 07:03.870
It has read it in as a single line of text.

84
07:03.890 --> 07:06.380
So this time there is no commas between the different words.

85
07:10.630 --> 07:17.410
If we want to write to a file then we use a ofstream. Again, we give the name of the file that we

86
07:17.410 --> 07:20.080
want to use as the argument to the constructor.

87
07:23.100 --> 07:28.650
So this will open the communication channel between the program and the file. And this time it is going

88
07:28.650 --> 07:30.870
to send data from the program to the file.

89
07:31.760 --> 07:34.650
Again, we need to check the state of the stream.

90
07:34.950 --> 07:41.700
We need to check that the stream could successfully open the file. And then, to use the stream, we just

91
07:41.700 --> 07:44.520
use the left shift operator to send data to it.

92
07:48.360 --> 07:51.570
So, for example, we could create a vector of strings.

93
07:52.110 --> 07:55.680
We have a range for loop, which iterates over the vector.

94
07:56.250 --> 08:00.720
So each time through the loop, this will be the next string from the vector.

95
08:01.350 --> 08:05.430
And then this will cause that string to be sent to the file.

96
08:12.760 --> 08:19.150
So here is that text. The solution Explorer is covering the attribute, actually, but I am sure you can work

97
08:19.150 --> 08:20.050
out what should be in there!

98
08:20.860 --> 08:27.400
So we need to include the fstream header to get the file streams, and then string for the string object

99
08:27.400 --> 08:28.930
and vector for the vector.

100
08:31.040 --> 08:36.950
So if we run this program - and by the way, make sure that this file does not have any data that you

101
08:36.950 --> 08:43.040
want to keep. When we open a file for writing, that will overwrite any data that is already in the file.

102
08:47.880 --> 08:54.960
So if we run that, then - nothing appears to have happened! But it has actually generated the file.

103
08:55.320 --> 08:59.640
This file will be in the same directory, the same folder as the one that the program ran in.

104
09:00.690 --> 09:02.790
So in [Visual Studio], we can do Projects,

105
09:03.760 --> 09:10.720
Add Existing Item, and then we see that there is the file that we just created. In the directory where

106
09:10.720 --> 09:15.520
the program read. And then that has now been added to the project.

107
09:15.580 --> 09:21.910
So it is part of the solution. And then we can just look at that file. And we have "The", comma "quick", comma

108
09:21.910 --> 09:22.240
"brown."

109
09:25.080 --> 09:30.330
So each of the elements of this vector has been sent to the file, followed by a comma.

110
09:33.490 --> 09:40.390
And finally, the destructor of the file stream class. When the destructor is called, the file is automatically

111
09:40.390 --> 09:40.810
closed.

112
09:41.230 --> 09:44.410
So this will happen just before the actual stream object is destroyed.

113
09:45.220 --> 09:50.490
If this is an output stream, then this will make sure that any data that is hanging around in memory

114
09:50.500 --> 09:52.420
buffers will get written to the file.

115
09:54.570 --> 09:59.850
So this means that if we have a file stream object, we do not actually need to call close.

116
10:00.270 --> 10:04.620
We can just leave it and let it go out of scope and it will automatically be handled.

117
10:05.240 --> 10:09.960
However, it is a good idea to explicitly put in a call to close, as that will make it clear that

118
10:09.960 --> 10:12.540
we have actually finished with using that particular file.

119
10:14.310 --> 10:16.440
Okay, so that's it's for this video.

120
10:16.890 --> 10:20.250
I'll see you next time, but meanwhile, keep coding!