1 00:00:00,580 --> 00:00:02,490 Let's play around with the console a little bit. 2 00:00:04,000 --> 00:00:08,110 We'll delete what we did before and we'll print out hello world. 3 00:00:08,110 --> 00:00:08,940 I know, I know, 4 00:00:08,940 --> 00:00:12,126 you've probably done this at least ten times already but bear with me. 5 00:00:12,126 --> 00:00:19,690 Console.WriteLine and "Hello, world!". 6 00:00:19,690 --> 00:00:22,470 So what is the console class exactly? 7 00:00:22,470 --> 00:00:25,380 We've been using it this whole time in other courses, but 8 00:00:25,380 --> 00:00:29,150 what is actually going on when we tell it to read or write? 9 00:00:29,150 --> 00:00:33,400 Well, we can gather that read is the input part of our IO and 10 00:00:33,400 --> 00:00:35,970 write is the output, right? 11 00:00:35,970 --> 00:00:40,140 Let's take a look at the documentation on the Console class by hitting F1. 12 00:00:42,840 --> 00:00:47,740 Represents the standard input, output, and error streams for console applications. 13 00:00:47,740 --> 00:00:51,947 So not only do we have an input and output stream, we've also got an error stream. 14 00:00:53,240 --> 00:00:57,400 Let's go back to our code and open up our data.text file. 15 00:00:59,220 --> 00:01:05,770 But we'll take Hello, world from our String here and cut it with Ctrl+X. 16 00:01:05,770 --> 00:01:07,139 Paste it here with Ctrl+V. 17 00:01:10,373 --> 00:01:15,132 Okay, now we can change the input stream of our console with a method on 18 00:01:15,132 --> 00:01:17,405 the console class called SetIn. 19 00:01:20,350 --> 00:01:22,120 But we need a stream first. 20 00:01:22,120 --> 00:01:24,220 We need an input stream from our text file. 21 00:01:25,280 --> 00:01:30,730 There's a handy class we can use called Stream reader, Stream reader. 22 00:01:33,410 --> 00:01:38,340 Let's check out its documentation by hitting F1, implements a text 23 00:01:38,340 --> 00:01:42,930 reader that reads characters from a byte stream in a particular encoding. 24 00:01:42,930 --> 00:01:45,500 We'll talk about what it means by encoding in a bit but 25 00:01:45,500 --> 00:01:46,920 let's take a look at the constructors. 26 00:01:48,140 --> 00:01:50,000 That's a lot of constructors. 27 00:01:50,000 --> 00:01:52,590 We're looking for one that takes a file name. 28 00:01:53,845 --> 00:01:58,220 Well, here's a string, initializes a new instance of the stream reader class for 29 00:01:58,220 --> 00:01:59,220 the specified file name. 30 00:02:00,300 --> 00:02:01,120 We can try and use that. 31 00:02:02,200 --> 00:02:03,970 First we need to get the filename. 32 00:02:03,970 --> 00:02:07,280 We can use the file info class to get a single file and 33 00:02:07,280 --> 00:02:09,795 make sure it exists before we try to read it. 34 00:02:09,795 --> 00:02:12,425 We'll instantiate a new file info objects. 35 00:02:12,425 --> 00:02:21,080 So, file = new FileInfo and it looks like it takes a file name in the constructor, 36 00:02:22,290 --> 00:02:27,800 says the fully qualified name of the new file or the relative file name. 37 00:02:27,800 --> 00:02:31,090 Do not end path with the directory separator character. 38 00:02:31,090 --> 00:02:31,590 Got it. 39 00:02:32,900 --> 00:02:37,310 We'll create a new variable to hold the file name, var filename, 40 00:02:38,480 --> 00:02:42,890 we'll use the Path.Combine method, Path.Combine, 41 00:02:42,890 --> 00:02:48,519 we'll give it directory.FullName and 42 00:02:48,519 --> 00:02:57,350 the name of our file, which is data.txt and semi-colon. 43 00:02:57,350 --> 00:03:00,790 It's a good idea to use Path.Combine when you wanna filename 44 00:03:00,790 --> 00:03:04,460 because it will add the backslashes for you if they're missing. 45 00:03:04,460 --> 00:03:09,710 We can pass the fileName into the FileInfo constructor, and to be safe, 46 00:03:09,710 --> 00:03:13,620 we should check and make sure the file exists before trying to access it. 47 00:03:13,620 --> 00:03:16,745 Let's see if there's a property on file that we can use. 48 00:03:16,745 --> 00:03:20,260 file.Exists. 49 00:03:20,260 --> 00:03:22,860 It returns a boolean, so we can write an IF statement, 50 00:03:24,280 --> 00:03:29,020 if file.Exists, and open close curly brace. 51 00:03:31,290 --> 00:03:33,155 Now we can use our StreamReader class. 52 00:03:33,155 --> 00:03:37,659 var reader = new StreamReader, and 53 00:03:37,659 --> 00:03:42,163 we'll pass it the file.FullName, 54 00:03:42,163 --> 00:03:48,710 then we can use the SetIn method of the console class. 55 00:03:48,710 --> 00:03:56,252 Console.SetIn, and we'll pass it the reader. 56 00:03:56,252 --> 00:03:57,890 We'll delete this down here, too. 57 00:03:59,320 --> 00:04:03,939 Now that our console input stream is set to our data.txt file, 58 00:04:03,939 --> 00:04:07,875 we'll write the contents of the file to the console. 59 00:04:07,875 --> 00:04:11,989 Console.WriteLine and 60 00:04:11,989 --> 00:04:15,713 Console.ReadLine. 61 00:04:18,928 --> 00:04:22,330 And semi-colon. 62 00:04:22,330 --> 00:04:25,640 There's one final thing that we should do before we try to run this. 63 00:04:26,920 --> 00:04:29,680 There is a method called close that we should call 64 00:04:29,680 --> 00:04:31,140 once we're done with the stream reader. 65 00:04:32,140 --> 00:04:36,450 What this does is mostly self-explanatory, it closes the stream and 66 00:04:36,450 --> 00:04:40,390 it also releases the resources that are being used to read the stream. 67 00:04:41,730 --> 00:04:46,090 When we deal with streams and files, we're using unmanaged memory. 68 00:04:46,090 --> 00:04:49,960 In .NET, objects aren't cleaned up immediately when they're no longer needed. 69 00:04:51,040 --> 00:04:55,160 It's more efficient to only clean up those objects when the computer is in need of 70 00:04:55,160 --> 00:05:00,210 the memory, so it will wait as long as possible before cleaning up these objects. 71 00:05:00,210 --> 00:05:03,550 It's very difficult to predict when this might happen. 72 00:05:03,550 --> 00:05:05,420 The part of .NET responsible for 73 00:05:05,420 --> 00:05:08,680 cleaning up these objects is called the garbage collector. 74 00:05:08,680 --> 00:05:13,130 Files are unmanaged, meaning that they're not managed by the garbage collector. 75 00:05:13,130 --> 00:05:17,230 We have to tell the garbage collector that it can take out our trash, and 76 00:05:17,230 --> 00:05:20,080 we do that by calling the close method. 77 00:05:20,080 --> 00:05:23,570 This will also let other programs on the computer use the file. 78 00:05:25,460 --> 00:05:29,590 One way to know if something is unmanaged is to check to see if it implements 79 00:05:29,590 --> 00:05:32,500 the interface IDisposable. 80 00:05:32,500 --> 00:05:36,550 Let's click on StreamReader and go to definition. 81 00:05:37,770 --> 00:05:41,485 It inherits from text reader, let's go to definition, 82 00:05:41,485 --> 00:05:46,410 aha, there it is, IDisposable, 83 00:05:46,410 --> 00:05:51,385 though an easier way to tell is to just check intellisense to see if it exists. 84 00:05:51,385 --> 00:05:55,890 Reader.Close. 85 00:05:55,890 --> 00:05:57,110 So now we just need to call it. 86 00:05:58,770 --> 00:06:03,800 But what would happen if an exception is thrown after our StreamReader is created, 87 00:06:03,800 --> 00:06:06,690 but before our call to close it? 88 00:06:06,690 --> 00:06:11,450 Close would never be called and we'd never an open file with no way to close it. 89 00:06:11,450 --> 00:06:16,380 In order to ensure that Close is called, even in the event of an exception, 90 00:06:16,380 --> 00:06:19,135 we need to wrap this code in a try finally. 91 00:06:19,135 --> 00:06:26,609 Try, And finally 92 00:06:30,428 --> 00:06:35,090 The finally block guarantees that any code inside of it will get executed, 93 00:06:35,090 --> 00:06:38,060 even if there's an exception in our try block. 94 00:06:39,160 --> 00:06:42,060 You can use it with or without a catch block. 95 00:06:42,060 --> 00:06:45,960 But instead of having to call the close method, 96 00:06:45,960 --> 00:06:47,910 there's an even better way to do this. 97 00:06:48,910 --> 00:06:53,160 We can declare and instantiate the disposable object with a using statement 98 00:06:53,160 --> 00:06:54,390 surrounding a block of code. 99 00:06:55,870 --> 00:07:02,390 So up here, using and then at the end, 100 00:07:02,390 --> 00:07:07,890 Close paren and then our block of code and we can move our 101 00:07:10,450 --> 00:07:13,420 try block in there and we can delete all of this. 102 00:07:16,520 --> 00:07:20,160 >> When the program gets to the final curly brace of the using block, 103 00:07:20,160 --> 00:07:24,230 the dispose method of the stream reader object will be called. 104 00:07:24,230 --> 00:07:28,138 The dispose method will then call the close method, and the file will be closed. 105 00:07:28,138 --> 00:07:31,069 So here when we call Console.ReadLine, 106 00:07:31,069 --> 00:07:37,100 instead of reading from the prompt, it's gonna read from our text file. 107 00:07:37,100 --> 00:07:39,295 Let's run it to see what happens. 108 00:07:39,295 --> 00:07:43,450 Ctrl+F5 and there's our Hello, world. 109 00:07:45,000 --> 00:07:49,880 So what happens when we try to read from the stream after our using blog? 110 00:07:49,880 --> 00:07:50,525 Let's try it out. 111 00:07:50,525 --> 00:07:57,214 Console.ReadLine. 112 00:07:57,214 --> 00:08:02,397 And again we'll run with Ctrl+F5. 113 00:08:02,397 --> 00:08:03,593 No. 114 00:08:03,593 --> 00:08:09,180 We get an ObjectDisposedException: Cannot read from a closed TextReader. 115 00:08:09,180 --> 00:08:11,210 The stream was closed by our using statement.