Using Files in C# Variables are useful for programmers to store temporary or volatile data while the program is executing and GUI controls can be used to gather input from users or display output. Now we need a mechanism to store and retrieve data between program executions. Secondary (non-volatile) storage is used by many programs as results need to be stored as a report or possibly used by other programs. Data is also often provided in files and not from end-user interactions. FILE TYPES There are two main types of files: text files and binary files. A text file contains data that has been encoded using a scheme called Unicode. A binary file contains data that cannot be translated into text and it is usually encoded using an application or format specific technique (eg. JPEG or PNG files). GENERAL FILE ACCESS TECHNIQUES Files can be accessed sequentially (in order from start to finish) or randomly (known as random or direct access file access). We will focus on using sequentially accessed text files in our applications. Files are stored within folders and directories on physical storage devices on a computer using the filename standards for the given operating system (eg. Windows, Linux, and Mac OSX have different file naming conventions.) For our programs we will use the .txt extension to indicate to the user that the file is a text file. C# FILE ACCESS A file object is a C# object that must be created to store or retrieve data from a file in the operating system. IMPORTANT NOTE To use the file management capabilities of the .NET Framework in C# you must add the following directive (statement) at the beginning of your program: using System.IO; The directive shown above will ensure the necessary classes are available for your program. Writing Data to a File The StreamWriter class will be used to create a file object and the WriteLine() method will be used to write data sequentially to a text file. Try the following code in a Console Application called "file_courses". The key new concepts so far in the code are shown with the arrows. We must first add the directive to ensure we can use the File interfaces. (line 5) Next, we create a StreamWriter object. (line 19) Finally, we create a File object using the File.CreateText() method (line 20) The name of the file can be an absolute path (ie. file that includes the drive letter or root folder) or a relative path. In our example, a relative path is given. The file will be created in the same directory were the program is executed. During development time this is usually under your user directory / Visual Studio XXXX/Projects/Project Name/Solution Name/bin/Debug. After line 20 we have an object called outputFile that we can now use to store / write data with. The methods are Write() and WriteLine() which is the same as the Console class provided to direct information to the screen. Examine the next section of code to see a "best practice" for obtaining numeric user input with full validation. The user is asked how many courses they are taking. The int.TryParse() method is used to ensure the data can be converted to an integer. Then the numeric data is checked to ensure it is positive. 2 We are now ready to use a counted loop (FOR STATEMENT) to obtain the name of the courses and write them to a file. Here we see the output file object being used to write data to the file (line 48) and then when the user data is complete the file is closed (line 52). 3 Error Handling and Files There are some common issues encountered by programs that use files. lack of storage available where the file is created/updated invalid file names device may no longer be available (USB Flash drive removed while the file is being written) To handle these runtime errors we would use exception handling. In the code shown above the filename is invalid and the exception will be caught and an error message displayed to the user. Appending data to an existing file Each time you execute the courses program the previous file contents are erased. Many times you simply want to open an existing file and append new data. To append data simply open the file using the following statement: appendFile = File.AppendText("courses.txt"); Notice how the AppendText() method is used instead of the CreateText() method. The WriteLine() methods can be used to append data to the end of the file. Reading data from files To read data from text files simply open the file using the following statement: marksFile = File.OpenText("marks.txt"); The ReadLine() method can be used to read the data. Ensure that if the data is to be handled as numeric data the appropriate Parse() or TryParse() method is used for data conversion. 4 Do you see a problem with this approach? What if we don't know how many marks are in the file? We need a way of reading all of the data from a file until we reach the end of the file. Thankfully, this is easily done using the EndofStream boolean property of the file object. On line 47 we continue to read data from the file until we reach the end of the Stream. Exercises: 1. Create a console application that will generate 500 random numbers from 1-100 (inclusive) and as the numbers are generated the application will write each number to a file called "numbers.txt". You can use a for statement in this application. 2. Create a console application that will then open and read the numbers.txt file and determine how many of the numbers are even. The applications should be executable independently. Use a while loop with the EndofStream Boolean property for this application. 5