{"captions":[{"content":"[File I/O]","startTime":0,"duration":2000,"startOfParagraph":false},{"content":"[Jason Hirschhorn, Harvard University]","startTime":2000,"duration":2000,"startOfParagraph":false},{"content":"[This is CS50, CS50.TV]","startTime":4000,"duration":3000,"startOfParagraph":false},{"content":"When we think of a file, what comes to mind is a Microsoft Word document,","startTime":7000,"duration":4000,"startOfParagraph":false},{"content":"a JPEG image, or an MP3 song,","startTime":11000,"duration":3000,"startOfParagraph":false},{"content":"and we interact with each of these types of files in different ways. ","startTime":14000,"duration":3000,"startOfParagraph":false},{"content":"For example, in a Word document we add text ","startTime":17000,"duration":3000,"startOfParagraph":false},{"content":"while with a JPEG image we might crop out the edges or retouch the colors. ","startTime":20000,"duration":4000,"startOfParagraph":false},{"content":"Yet under the hood all of the files in our computer are nothing more","startTime":24000,"duration":4000,"startOfParagraph":false},{"content":"than a long sequence of zeros and ones. ","startTime":28000,"duration":3000,"startOfParagraph":false},{"content":"It's up to the specific application that interacts with the file","startTime":31000,"duration":2000,"startOfParagraph":false},{"content":"to decide how to process this long sequence and present it to the user. ","startTime":33000,"duration":5000,"startOfParagraph":false},{"content":"On one hand, a document may look at just one byte,","startTime":38000,"duration":3000,"startOfParagraph":false},{"content":"or 8 zeros and ones, and display an ASCII character on the screen.","startTime":41000,"duration":4000,"startOfParagraph":false},{"content":"On the other hand, a bitmap image may look at 3 bytes,","startTime":45000,"duration":3000,"startOfParagraph":false},{"content":"or 24 zeros and ones, ","startTime":48000,"duration":2000,"startOfParagraph":false},{"content":"and interpret them as 3 hexadecimal numbers","startTime":50000,"duration":3000,"startOfParagraph":false},{"content":"that represent the values for red, green, and blue","startTime":53000,"duration":3000,"startOfParagraph":false},{"content":"in one pixel of an image. ","startTime":56000,"duration":2000,"startOfParagraph":false},{"content":"Whatever they may look like on your screen, at their core, ","startTime":58000,"duration":3000,"startOfParagraph":false},{"content":"files are nothing more than a sequence of zeros and ones.","startTime":61000,"duration":4000,"startOfParagraph":false},{"content":"So let's dive in and look at how we actually manipulate these zeros and ones","startTime":65000,"duration":3000,"startOfParagraph":false},{"content":"when it comes to writing to and reading from a file. ","startTime":68000,"duration":4000,"startOfParagraph":false},{"content":"I'll start by breaking it down into a simple 3-part process. ","startTime":72000,"duration":3000,"startOfParagraph":true},{"content":"Next, I'll dive into two code examples that demonstrate these three parts. ","startTime":75000,"duration":4000,"startOfParagraph":false},{"content":"Finally, I'll review the process and some of its most important details. ","startTime":79000,"duration":4000,"startOfParagraph":false},{"content":"As with any file that sits on your desktop, ","startTime":83000,"duration":2000,"startOfParagraph":false},{"content":"the first thing to do is to open it. ","startTime":85000,"duration":3000,"startOfParagraph":false},{"content":"In C we do this by declaring a pointer to a predefined struct","startTime":88000,"duration":3000,"startOfParagraph":false},{"content":"that represents a file on disk. ","startTime":91000,"duration":2000,"startOfParagraph":false},{"content":"In this function call, we also decide whether we want to write to or read from the file. ","startTime":93000,"duration":5460,"startOfParagraph":false},{"content":"Next, we do the actual reading and writing. ","startTime":98460,"duration":3200,"startOfParagraph":false},{"content":"There are a number of specialized functions we can use in this part, ","startTime":101660,"duration":3140,"startOfParagraph":false},{"content":"and almost all of them start with the letter F, which stands for file. ","startTime":104800,"duration":3990,"startOfParagraph":false},{"content":"Last, akin to the little red X in the top corner of the files open on your computer, ","startTime":108790,"duration":4770,"startOfParagraph":false},{"content":"we close the file with a final function call. ","startTime":113560,"duration":3120,"startOfParagraph":false},{"content":"Now that we have a general idea of what we're going to do, ","startTime":116680,"duration":2860,"startOfParagraph":false},{"content":"let's dive into the code. ","startTime":119540,"duration":2460,"startOfParagraph":false},{"content":"In this directory, we have two C files and their corresponding executable files. ","startTime":122000,"duration":4100,"startOfParagraph":true},{"content":"The typewriter program takes one command line argument,","startTime":126100,"duration":3610,"startOfParagraph":false},{"content":"the name of the document we want to create. ","startTime":129710,"duration":2350,"startOfParagraph":false},{"content":"In this case, we'll call it doc.txt. ","startTime":132060,"duration":4100,"startOfParagraph":false},{"content":"Let's run the program and enter a couple of lines. ","startTime":136160,"duration":2920,"startOfParagraph":false},{"content":"Hi. My name is Jason. ","startTime":139080,"duration":4580,"startOfParagraph":false},{"content":"Finally, we'll type \"quit.\" ","startTime":143660,"duration":3050,"startOfParagraph":false},{"content":"If we now list all of the files in this directory, ","startTime":146710,"duration":3010,"startOfParagraph":false},{"content":"we see that a new document exists called doc.txt. ","startTime":149720,"duration":4050,"startOfParagraph":false},{"content":"That's the file this program just created.","startTime":154190,"duration":1920,"startOfParagraph":false},{"content":"And of course, it too is nothing more than a long sequence of zeros and ones.","startTime":156110,"duration":4410,"startOfParagraph":false},{"content":"If we open this new file, ","startTime":161100,"duration":2160,"startOfParagraph":false},{"content":"we see the 3 lines of code we entered into our program--","startTime":163260,"duration":2610,"startOfParagraph":false},{"content":"Hi. May name is Jason. ","startTime":166060,"duration":3000,"startOfParagraph":false},{"content":"But what's actually going on when typewriter.c runs? ","startTime":169580,"duration":2510,"startOfParagraph":false},{"content":"The first line of interest for us is line 24. ","startTime":172810,"duration":2710,"startOfParagraph":false},{"content":"In this line, we declare our file pointer. ","startTime":175560,"duration":2930,"startOfParagraph":false},{"content":"The function that returns this pointer, fopen, takes two arguments. ","startTime":179080,"duration":4060,"startOfParagraph":false},{"content":"The first is the file name including the file extension if appropriate. ","startTime":183140,"duration":4300,"startOfParagraph":false},{"content":"Recall that a file extension does not influence the file at its lowest level.","startTime":187440,"duration":3540,"startOfParagraph":false},{"content":"We're always dealing with a long sequence of zeros and ones. ","startTime":190980,"duration":3660,"startOfParagraph":false},{"content":"But it does influence how files are interpreted and what applications are used to open them. ","startTime":194640,"duration":4990,"startOfParagraph":false},{"content":"The second argument to fopen is a single letter ","startTime":199630,"duration":2660,"startOfParagraph":false},{"content":"that stands for what we plan to do after we open the file.","startTime":202290,"duration":3010,"startOfParagraph":false},{"content":"There are three options for this argument--W, R, and A. ","startTime":205300,"duration":5330,"startOfParagraph":false},{"content":"We've chosen w in this case because we want to write to the file. ","startTime":210630,"duration":4270,"startOfParagraph":false},{"content":"R, as you can probably guess, is for reading to the file. ","startTime":214900,"duration":3920,"startOfParagraph":false},{"content":"And a is for appending to the file. ","startTime":218820,"duration":2940,"startOfParagraph":false},{"content":"While both w and a may be used for writing to files,","startTime":221760,"duration":3200,"startOfParagraph":false},{"content":"w will start writing from the beginning of the file ","startTime":224960,"duration":2500,"startOfParagraph":false},{"content":"and potentially overwrite any data that have previously been stored. ","startTime":227460,"duration":3350,"startOfParagraph":false},{"content":"By default, the file we open, if it doesn't already exist, ","startTime":230810,"duration":3260,"startOfParagraph":false},{"content":"is created in our present working directory. ","startTime":234070,"duration":3110,"startOfParagraph":false},{"content":"However, if we want to access or create a file in a different location, ","startTime":237180,"duration":3360,"startOfParagraph":false},{"content":"in the first argument of fopen, ","startTime":240540,"duration":2110,"startOfParagraph":false},{"content":"we may specify a file path in addition to the file name. ","startTime":242650,"duration":3190,"startOfParagraph":false},{"content":"While the first part of this process is only one line of code long, ","startTime":245840,"duration":3650,"startOfParagraph":false},{"content":"it's always good practice to include another set of lines","startTime":249490,"duration":2860,"startOfParagraph":false},{"content":"that check to ensure that the file was successfully opened or created. ","startTime":252350,"duration":3580,"startOfParagraph":false},{"content":"If fopen returns null, we wouldn't want to forge ahead with our program,","startTime":255930,"duration":4370,"startOfParagraph":false},{"content":"and this may happen if the operating system is out of memory","startTime":260300,"duration":2970,"startOfParagraph":false},{"content":"or if we try to open a file in a directory for which we didn't have the proper permissions. ","startTime":263270,"duration":4670,"startOfParagraph":false},{"content":"Part two of the process takes place in typewriter's while loop. ","startTime":267940,"duration":3840,"startOfParagraph":true},{"content":"We use a CS50 library function to get input from the user,","startTime":271780,"duration":3220,"startOfParagraph":false},{"content":"and assuming they don't want to quit the program, ","startTime":275000,"duration":2190,"startOfParagraph":false},{"content":"we use the function fputs to take the string and write it to the file. ","startTime":277190,"duration":4750,"startOfParagraph":false},{"content":"fputs is only one of the many functions we could use to write to the file. ","startTime":281940,"duration":4760,"startOfParagraph":false},{"content":"Others include fwrite, fputc, and even fprintf. ","startTime":286700,"duration":5220,"startOfParagraph":false},{"content":"Regardless of the particular function we end up using, though, ","startTime":291920,"duration":2920,"startOfParagraph":false},{"content":"all of them need to know, via their arguments, ","startTime":294840,"duration":2640,"startOfParagraph":false},{"content":"at least two things--","startTime":297480,"duration":2190,"startOfParagraph":false},{"content":"what needs to be written and where it needs to be written to. ","startTime":299670,"duration":3470,"startOfParagraph":false},{"content":"In our case, input is the string that needs to be written","startTime":303140,"duration":4100,"startOfParagraph":false},{"content":"and fp is the pointer that directs us to where we're writing. ","startTime":307240,"duration":4050,"startOfParagraph":false},{"content":"In this program, part two of the process is rather straightforward. ","startTime":311290,"duration":4040,"startOfParagraph":false},{"content":"We're simply taking a string from the user","startTime":315330,"duration":2030,"startOfParagraph":false},{"content":"and adding it directly to our file with little-to-no input validation or security checks. ","startTime":317360,"duration":4760,"startOfParagraph":false},{"content":"Often, however, part two will take up the bulk of your code. ","startTime":322120,"duration":4040,"startOfParagraph":false},{"content":"Finally, part three is on line 58, where we close the file. ","startTime":326160,"duration":4420,"startOfParagraph":false},{"content":"Here we call fclose and pass it our original file pointer. ","startTime":330580,"duration":4280,"startOfParagraph":false},{"content":"In the subsequent line, we return zero, signalling the end of our program. ","startTime":334860,"duration":4640,"startOfParagraph":false},{"content":"And, yes, part three is as simple as that. ","startTime":339500,"duration":3130,"startOfParagraph":false},{"content":"Let's move on to reading from files. ","startTime":342630,"duration":2630,"startOfParagraph":true},{"content":"Back in our directory we have a file called printer.c. ","startTime":345260,"duration":2960,"startOfParagraph":false},{"content":"Let's run it with the file we just created--","startTime":348220,"duration":2690,"startOfParagraph":false},{"content":"doc.txt. ","startTime":350910,"duration":2440,"startOfParagraph":false},{"content":"This program, as the name suggests, will simply print out the contents of the file passed to it. ","startTime":353350,"duration":4800,"startOfParagraph":false},{"content":"And there we have it. ","startTime":358150,"duration":2080,"startOfParagraph":false},{"content":"The lines of code we had typed earlier and saved in doc.txt. ","startTime":360230,"duration":3550,"startOfParagraph":false},{"content":"Hi. My name is Jason. ","startTime":363780,"duration":3200,"startOfParagraph":false},{"content":"If we dive into printer.c, ","startTime":366980,"duration":2140,"startOfParagraph":false},{"content":"we see that a lot of the code looks similar to what we just walked through in typewriter.c. ","startTime":369120,"duration":4450,"startOfParagraph":false},{"content":"Indeed line 22, where we opened the file, ","startTime":373570,"duration":3150,"startOfParagraph":false},{"content":"and line 39, where we closed the file, ","startTime":376720,"duration":2500,"startOfParagraph":false},{"content":"are both almost identical to typewriter.c, save for fopen second argument. ","startTime":379220,"duration":4670,"startOfParagraph":false},{"content":"This time we're reading from a file, ","startTime":383890,"duration":2620,"startOfParagraph":false},{"content":"so we have chosen r instead of w. ","startTime":386510,"duration":2530,"startOfParagraph":false},{"content":"Thus, let's focus on the second part of the process. ","startTime":389040,"duration":2910,"startOfParagraph":false},{"content":"In line 35, as the second condition in our 4 loop, ","startTime":391950,"duration":4110,"startOfParagraph":false},{"content":"we make a call to fgets, ","startTime":396060,"duration":2530,"startOfParagraph":false},{"content":"the companion function to fputs from before. ","startTime":398590,"duration":3600,"startOfParagraph":false},{"content":"This time we have three arguments. ","startTime":402190,"duration":2470,"startOfParagraph":false},{"content":"The first is the pointer to the array of characters where the string will be stored. ","startTime":404660,"duration":4150,"startOfParagraph":false},{"content":"The second is the maximum number of characters to be read. ","startTime":408810,"duration":3860,"startOfParagraph":false},{"content":"And the third is the pointer to the file with which we're working. ","startTime":412670,"duration":3340,"startOfParagraph":false},{"content":"You'll notice that the for loop ends when fgets returns null. ","startTime":416010,"duration":4770,"startOfParagraph":false},{"content":"There are two reason that this may have happened. ","startTime":420780,"duration":2160,"startOfParagraph":false},{"content":"First, an error may have occurred. ","startTime":422940,"duration":2440,"startOfParagraph":false},{"content":"Second, and more likely, the end of the file was reached and no more characters were read. ","startTime":425380,"duration":5360,"startOfParagraph":false},{"content":"In case you're wondering, two functions do exist that allow us to tell ","startTime":430740,"duration":3300,"startOfParagraph":false},{"content":"which reason is the cause for this particular null pointer. ","startTime":434040,"duration":3120,"startOfParagraph":false},{"content":"And, not surprisingly, since they have to do with working with files, ","startTime":437160,"duration":3930,"startOfParagraph":false},{"content":"both the ferror function and the feof function start with the letter f. ","startTime":441090,"duration":5850,"startOfParagraph":false},{"content":"Finally, before we conclude, one quick note about the end of file function,","startTime":446940,"duration":5190,"startOfParagraph":true},{"content":"which, as just mentioned, is written as feof. ","startTime":452130,"duration":4560,"startOfParagraph":false},{"content":"Often you'll find yourself using while and for loops to progressively read your way through files. ","startTime":456690,"duration":4860,"startOfParagraph":false},{"content":"Thus, you'll need a way to end these loops after you reach the end of these files. ","startTime":461550,"duration":4240,"startOfParagraph":false},{"content":"Calling feof on your file pointer and checking to see if it's true","startTime":465790,"duration":4720,"startOfParagraph":false},{"content":"would do just that. ","startTime":470510,"duration":1800,"startOfParagraph":false},{"content":"Thus, a while loop with the condition (!feof(fp)) might seem like a perfectly appropriate solution. ","startTime":472310,"duration":7510,"startOfParagraph":false},{"content":"However, say we have one line left in our text file. ","startTime":479820,"duration":3950,"startOfParagraph":false},{"content":"We'll enter our while loop and everything will work out as planned. ","startTime":483770,"duration":3360,"startOfParagraph":false},{"content":"On the next round through, our program will check to see if feof of fp is true, ","startTime":487130,"duration":5620,"startOfParagraph":false},{"content":"but--and this is the crucial point to understand here--","startTime":492750,"duration":2680,"startOfParagraph":false},{"content":"it won't be true just yet. ","startTime":495430,"duration":2340,"startOfParagraph":false},{"content":"That's because the purpose of feof is not to check ","startTime":497770,"duration":3340,"startOfParagraph":false},{"content":"if the next call to a read function will hit the end of the file, ","startTime":501110,"duration":3290,"startOfParagraph":false},{"content":"but rather to check whether or not the end of the file has already been reached. ","startTime":504400,"duration":3790,"startOfParagraph":false},{"content":"In the case of this example, ","startTime":508190,"duration":1950,"startOfParagraph":false},{"content":"reading the last line of our file goes perfectly smoothly,","startTime":510140,"duration":2640,"startOfParagraph":false},{"content":"but the program doesn't yet know that we've hit the end of our file. ","startTime":512780,"duration":3430,"startOfParagraph":false},{"content":"It's not until it does one additional read that it counters the end of the file. ","startTime":516210,"duration":4339,"startOfParagraph":false},{"content":"Thus, a correct condition would be the following: ","startTime":520549,"duration":2661,"startOfParagraph":false},{"content":"fgets and its three arguments--output, size of output, and fp--","startTime":523210,"duration":6120,"startOfParagraph":false},{"content":"and all of that not equal to null. ","startTime":529330,"duration":3240,"startOfParagraph":false},{"content":"This is the approach we took in printer.c, ","startTime":532570,"duration":2690,"startOfParagraph":false},{"content":"and in this case, after the loop exits, ","startTime":535260,"duration":2630,"startOfParagraph":false},{"content":"you could call feof or ferror to inform the user as to the specific reasoning for exiting this loop. ","startTime":537890,"duration":6400,"startOfParagraph":false},{"content":"Writing to and reading from a file is, at its most basic, ","startTime":544290,"duration":3810,"startOfParagraph":true},{"content":"a simple 3-part process. ","startTime":548100,"duration":2050,"startOfParagraph":false},{"content":"First, we open the file. ","startTime":550150,"duration":2380,"startOfParagraph":false},{"content":"Second, we put some things into our file or take some things out of it. ","startTime":552530,"duration":4210,"startOfParagraph":false},{"content":"Third, we close the file. ","startTime":556740,"duration":2460,"startOfParagraph":false},{"content":"The first and last parts are easy. ","startTime":559200,"duration":1970,"startOfParagraph":false},{"content":"The middle part is where the tricky stuff lies. ","startTime":561170,"duration":2750,"startOfParagraph":false},{"content":"And though underneath the hood we're always dealing with a long sequence of zeros and ones, ","startTime":563920,"duration":3840,"startOfParagraph":false},{"content":"it does help when coding to add a layer of abstraction","startTime":567760,"duration":2950,"startOfParagraph":false},{"content":"that turns the sequence into something that more closely resembles what we're used to seeing. ","startTime":570710,"duration":4640,"startOfParagraph":false},{"content":"For example, if we're working with a 24-bit bitmap file, ","startTime":575350,"duration":4220,"startOfParagraph":false},{"content":"we'll likely be reading or writing three bytes at a time. ","startTime":579570,"duration":3720,"startOfParagraph":false},{"content":"In which case, it would make sense to define and appropriately name","startTime":583290,"duration":3160,"startOfParagraph":false},{"content":"a struct that is 3 bytes large. ","startTime":586450,"duration":2530,"startOfParagraph":false},{"content":"Though working with files may seem complicated, ","startTime":588980,"duration":2430,"startOfParagraph":true},{"content":"utilizing them allows us to do something truly remarkable. ","startTime":591410,"duration":3120,"startOfParagraph":false},{"content":"We can change the state of the world outside our program, ","startTime":594530,"duration":4350,"startOfParagraph":false},{"content":"we can create something that lives beyond the life of our program, ","startTime":598880,"duration":2850,"startOfParagraph":false},{"content":"or we can even change something that was created before our program started running. ","startTime":601730,"duration":5460,"startOfParagraph":false},{"content":"Interacting with files is a truly powerful part of programming in C. ","startTime":607190,"duration":4020,"startOfParagraph":false},{"content":"and I'm excited to see what you're going to create with it in the code to come. ","startTime":611210,"duration":4090,"startOfParagraph":false},{"content":"My name is Jason Hirschhorn. This is CS50.","startTime":615300,"duration":4470,"startOfParagraph":false},{"content":"[CS50.TV]","startTime":619770,"duration":2000,"startOfParagraph":false},{"content":"[Laughter]","startTime":621770,"duration":4170,"startOfParagraph":true},{"content":"Okay. One take. Here we go. ","startTime":625940,"duration":3390,"startOfParagraph":false},{"content":"When we think of a file-- >>Oh, wait. Sorry. ","startTime":649000,"duration":3140,"startOfParagraph":false},{"content":"[Laughter] Okay. ","startTime":652140,"duration":4660,"startOfParagraph":false},{"content":"Hey there. ","startTime":666620,"duration":3350,"startOfParagraph":false},{"content":"When we think of a file--","startTime":673670,"duration":2640,"startOfParagraph":false},{"content":"When you think of a file-- Okay. Tell me when you're ready. ","startTime":677610,"duration":3100,"startOfParagraph":false},{"content":"Oh, great. ","startTime":680710,"duration":1810,"startOfParagraph":false},{"content":"Though reading from a teleprompter may seem--no. My bad. ","startTime":682520,"duration":3660,"startOfParagraph":false}]}