File I/O There’s more to life than the keyboard Interactive vs. file I/O • All of the programs we have seen or written thus far have assumed interaction with a user, who types in data at a keyboard and sees output on a screen • We can also receive data from, or send data to, the secondary storage devices on the computer • This type of input and output is called file I/O Stream objects • In Java, as in many programming languages, we envision data flowing past our program in a stream – Data coming into a program comes from one or more input streams – Data coming out of a program goes to one or more output streams • A stream object can represent an input or output device (such as the keyboard or screen), but it can also represent a secondary storage location – in other words, a file The file concept • We can envision a file as a special kind of container that can hold a collection of data or instructions • A file can also contain a collection of other files: such a file is called a directory or folder • An important point to remember is that Java considers a folder to be just another file File system organization • Under Windows and most other modern operating systems, information is stored on disk in a hierarchically ordered structure consisting of directories, subdirectories, and files • Disks are designated using letters – for example, C is typically the computer’s hard drive (or its primary partition), while A is traditionally a floppy disk • The Windows GUI portrays directories as folders, which can contain other folders or files File types • Text files are human-readable collections of data, which can be created (saved) and retrieved (opened) using a text editor • Binary files are usually not humanreadable; rather, they are collections of bits arranged in a format that can be read or written using a specific application program Example – text file A text file (source code from a Java program) Binary file example Java byte code (.class file) The file displayed below is a Word document. What type of file is it? A.Text B.Binary C.Neither D.Both Text files vs. binary files • Text files are coded in ASCII, and are therefore usually readable across different hardware platforms & applications • Binary files can be processed more efficiently by their native programs than text files, but are often platform & application-dependent • Java binary files are platform-independent; you can read them on any computer that has a Java Virtual Machine and the application code Text file I/O • We’ll begin by looking at the simplest case: writing text data to a file • When you intend to read or write files, you will need to use classes and methods from the java.io package, so begin with the following import statement: import java.io.*; PrintWriter and FileOutputStream • An object of type PrintWriter is the preferred means to represent a text file output stream, • The PrintWriter constructor requires a parameter of type FileOutputStream, which in turn has a constructor that requires a String parameter, specifiying a file name • Constructing a PrintWriter object on a specific FileOutputStream is called opening a file Example – opening an output file • I want to write some data to a file in the same folder as my program’s byte code; the file name is MyData.txt • I could use the following syntax to open the file (by creating a PrintWriter object named myFile): PrintWriter myFile = new PrintWriter(new FileOutputStream(“MyData.txt”); Breaking down the example • On the previous slide, two objects were created: – an anonymous FileOutputStream object – a PrintWriter object • In creating the first object, a FileNotFoundException (a subtype of IOException) can be thrown – this is a checked exception, so it must be handled with either a try/catch block or a throws clause Variation on example • It makes sense to use an anonymous FileOutputStream object (because it isn’t used anywhere else in the program) to create the PrintWriter object • However, it is really the creation of the FileOutputStream that throws the exception, and we could isolate just this line of code if we wanted to place it in a try block, as shown on the next slide Variation on example Scanner kb = new Scanner(System.in); String fileName; System.out.print (“Enter name for output file: “); fileName = kb.nextLine(); PrintWriter myFile; FileOutputStream myStream; try { myStream = new FileOutputStream(fileName); } catch (FileNotFoundException e) { System.out.println (“File could not be opened for output; closing program”); System.exit(1); } // ends catch block myFile = new PrintWriter(myStream); Notes on files & file organization under Windows • The way files are organized and stored on a computer depends on the computer’s operating system • Under windows, disk drives (both physical and virtual, such as partitions or network drives) are designated with a letter: – C: is usually the computer’s primary hard drive – A: is usually the floppy drive, if one exists Notes on files & file organization under Windows • Each disk is organized into a set of directories, or folders, with alphanumeric names • A folder can contain files and/or more folders, called subdirectories • We differentiate between a subdirectory and its containing directory, or a file and its containing directory, using backslash separators Examples • A file named text.txt in the documents subdirectory of the mystuff directory on the C: drive of the computer would be written as: C:\mystuff\documents\text.txt • A file named file.txt on a floppy disk, in the main directory, would be: A:\file.txt Windows file names & Java programs • The examples on the previous slide illustrate what a user should type in response to the prompt, “Enter a file name:” • Originally, we saw an example in which the file name was hard-coded into the program: PrintWriter myFile = new PrintWriter(new FileOutputStream(“MyData.txt”); Windows file names & Java programs • As the example indicated, the file in question “MyData.txt” was in the same directory as the Java program • If you want to hard-code a file name from a different disk or folder into a Java program, you need to be careful with the backslash (\) character • As we know, a backslash followed by a single character indicates an escape, or control character – for example, \n is the newline character Windows file names & Java programs • To hard-code the name of a file in a different folder or disk than your program, use two backslashes wherever a backslash should appear; for example: PrintWriter myFile = new PrintWriter(new FileOutputStream(“C:\\TextFiles\\MyData.txt”); Writing output to text files • Once a PrintWriter object has been instantiated, writing output to an open file is as simple as writing output to the screen • The methods print, println, and printf can be called on the PrintWriter object, just as they can be called on System.out • You can still call these same methods from System.out, so you can write to either a file or the screen in the same program Other PrintWriter methods • The close() method closes the stream’s connection to a file; it should be called before ending a program with an open file • Note that the same PrintWriter object can be used to open multiple files – you just have to close one file before you open another • If you wish to write to a file and read from it later, you must close it as an output file before opening it as an input file • The flush() method can be called to force a write to a file – this will clear the output buffer of all data currently in it Example import java.io.*; import java.util.*; public class WriteMyFile { public static void main (String [] args) throws FileNotFoundException { Scanner kb = new Scanner(System.in); String fName; System.out.print(“Enter output file name:”); fName = kb.nextLine(); PrintWriter pw = new PrintWriter(new FileOutputStream(fName)); System.out.println(“Here it is on the screen”); pw.println(“And here it is in the file”); pw.close(); } } Overwriting vs. appending to output files • The way you open a file (by calling the FileOutputStream constructor) determines whether you will create a new file, overwrite an existing file, or add contents to an existing file • If you call the constructor as we have been doing, with a single String argument, you will either create a new file or overwrite an existing one – the latter if a file by the specified name already exists • If you call the constructor with two arguments – a String and a true boolean expression – you will instead open the file to append to it, rather than replace it Example • Suppose the file created in the WriteMyFile example exists in the root directory of drive A and contains the text “And here it is in the file” • The following code: PrintWriter pw = new PrintWriter (new FileOutputStream(“A:\\myFile.txt”, true)); pw.println(“And here we go again”); pw.close(); would add text to the file; its contents would now be: And here it is in the file And here we go again General notes on examples • All of the examples so far have opened a file, written a single line to it, then closed the file • The examples are set up as they are to keep them short – they aren’t typical • Normally, we would write several lines of output to a file, first opening it, then closing it when our output is finished • In general, a file output stream is just like the standard output stream – we just have to remember to open it before we can use it, and close it when we’re done Reading input from a text file • Can use the same Scanner class we use for keyboard input to read from a text file • When reading from the keyboard, we create the Scanner object by passing its constructor an object representing the standard input stream: Scanner kb = new Scanner (System.in); • To read from a test file, we construct it by passing a FileInputStream object instead – in other words, we open an input file much the same way we open an output file Syntax & example • General syntax: Scanner scanner = new Scanner (new FileInputStream(name)); • Example: Scanner input = new Scanner (new FileInputStream(“C:\\myfiles\\data.txt”)); Notes on opening input files • Instantiating a FileInputStream object can throw the same type of exception (FileNotFoundException) as with a FileOutputStream object • As with output files, we can break down the process of opening an input file into smaller pieces; see next slide Example String fileName; Scanner kb = new Scanner (System.in); System.out.print(“Enter name of input file: ”); fileName = kb.nextLine(); try { FileInputStream inFileStream = new FileInputStream(fileName); } catch (FileNotFoundException e) { System.out.println(“Could not open input file – ending program”); System.exit(1); } Scanner inFile = new Scanner(inFileStream); Scanner methods • Once a Scanner object is open, you can call the same methods to read data from an input file as you have used to read data from the keyboard – for integers: nextInt() – for doubles: nextDouble() – for Strings: next() and nextLine() More Scanner methods • The Scanner class has several “look ahead” methods that can be used to determine: – whether or not there is more input to come – the nature of the input (number vs. text) • All of the following methods return a boolean value: – hasNextInt() – hasNextDouble() – hasNext() Example import java.util.*; public class IOTest { public static void main (String [] args) { Scanner kb = new Scanner (System.in); boolean end = false; while (!end) { System.out.print("Enter some text; enter a number to quit: "); if (kb.hasNextDouble()) end = true; else { String input = kb.nextLine(); System.out.println ("You entered: " + input); } } } } File input & EOF loops • The previous example used the difference between text and numeric input to determine the end of keyboard data • A more realistic, and much more common application, is the use of the hasNext() method(s) to determine whether or not there is more data to be read from a file Example Scanner inFile = new Scanner (new FileInputStream(“somefile.txt”)); String input; while (inFile.hasNextLine()) { input = inFile.nextLine(); // processing of input can occur here } inFile.close();