Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Lab 3 — File I/O with Binary and ASCII Files Part 1: Binary File I/O 1. Let’s do some interactive experiments with file I/O. First, download the file show.class from the course web page (under Labs/lab03) and put it on the Desktop. Then start DrJava, switch to the Interactions pane at the bottom of the window, and drag the separator bar to make the pane bigger. Then type the following lines at the DrJava prompt, exactly as shown: > > > > > import java.io.*; FileInputStream fis; FileOutputStream fos; DataInputStream dis; DataOutputStream dos; 2. We’ll start by testing the FileOutputStream class, which writes individual bytes to a file. Create a new file called “data.bin” (which will be a binary file, not a text file), write 42, and then look at the contents: > fos = new FileOutputStream(“data.bin”); > fos.write(42) > java show data.bin Next, write 127 and show the file again. Then repeat with 255. (Note: if you get tired of retyping the same lines over and over, just hit the up-arrow key to scroll backwards in your command history.) Now write -1. Notice that the exact same bit pattern gets written for 255 and -1. This is because negative integer values are represented in two’s complement form, and the two’s complement representation of -1 is the same as the unsigned integer representation of 255. Next, write 253 followed by -3 and view the file again. Next, write 258. Is the result what you expected? If not, explain. 3. Now let’s read the data back in. Close the file by typing fos.close(), and then reopen it as a FileInputStream object: > fis = new FileInputStream(“data.bin”); > java show data.bin Type fis.read() to read values from the file. Do this at least 10 times. Did you get any negative values back? What happened to them? What happens if you try to read beyond the end of the file? 4. Now let’s test the DataOutputStream class, which provides methods for writing different types of data values. Open a DataOutputStream and try the following tests: > dos = new DataOutputStream(new FileOutputStream(“data.bin”)); > java show data.bin > dos.writeInt(42) > java show data.bin > dos.writeInt(-3) > java show data.bin > dos.writeChar(‘A’) > java show data.bin > dos.writeByte(253) > java show data.bin How many bytes get written in each case? Make sure you understand the results after each step. 5. Now close the file and reopen it as a DataInputStream: > dis = new DataInputStream(new FileInputStream(“data.bin”)); > java show data.bin Try the following read operations and make sure you understand the results: > > > > dis.readInt() dis.readInt() dis.readChar() dis.readByte() Is the last value what you expected? If not, explain the result. 6. Now type the uppercase alphabet into DrJava’s editor window and save it under the name “alpha.txt”. Then open a DataInputStream and read in the characters with readChar(). What’s going on? > > > > > > dis = new DataInputStream(new FileInputStream(“alpha.txt”)); java show alpha.txt dis.readChar() dis.readChar() dis.readChar() dis.readChar() etc. Try some other tests on your own. Part 2: Building an Abstraction for ASCII File I/O For the rest of the lab, you will build an abstraction for reading and writing characters to/from ASCII text files. We discussed the interface for the classes ASCIIFileReader and ASCIIFileWriter in class this week. Skeleton code for these classes is available on the course web page under Labs/lab03. Your job is to provide an implementation. For testing purposes, you should also download CopyTextfile.java and Madlib.java, which use these classes to read and write text files character by character. ASCIIFileReader An ASCIIFileReader object creates the illusion of reading characters from a text file one at a time. To do this, it keeps track of several internal variables, one of which is a buffer that holds an entire line of text read from the file. The readChar() method retrieves the next available character from the buffer and returns it. However, if the buffer becomes empty, another line of text is automatically read from the file and saved in the buffer before the character is returned. We will use the following instance variables: private private private private private String buffer; int position; Scanner scan; boolean moreChars; int numCharsRead; Add these variable declarations to your ASCIIFileReader class definition. The buffer holds the most recent line of text read from the file. The position is the index of the next available character in the buffer, to be returned the next time readChar() is called. The Scanner is used “behind the scenes” to read lines of text from the file into the buffer, as needed. The moreChars flag is true if the ASCIIFileReader has characters available, which will normally be the case unless the Scanner runs out of lines. The numCharsRead counter keeps track of how many times readChar() has been called. You may assume that every line of a text file is terminated by a single ’\n’ (newline) character. This character is automatically removed by the Scanner’s nextLine() method, but your ASCIIFileReader’s readChar() method should still return these characters as if they had not been removed. The constructors for ASCIIFileReader and ASCIIFileWriter each take the name of a text file as a String, and throw a FileNotFoundException if the file cannot be opened for reading or writing. The ASCIIFileReader’s readChar() method should throw an EOFException if the user attempts to read characters beyond the end of the file. The ASCIIFileReader’s fillBuffer() method is a helper method that is called automatically whenever the buffer is empty and another line is needed from the text file. It also sets the moreChars flag to true or false, depending on whether the attempt to fill the buffer was successful. Since this method is a helper method that is not intended to be part of the public ASCIIFileReader interface, it is declared as private instead of public. The info() method should be used to help you debug your code. It simply prints out the current values of the internal state variables. ASCIIFileWriter The ASCIIFileWriter object creates the illusion of writing characters to a text file one at a time. It does not actually need to maintain a buffer, because it can simply use a PrintWriter object internally to directly write characters to the file whenever they are received by the writeChar method. Like ASCIIFileReader, however, it still needs to maintain an internal count of the number of characters written to the file. You can test your classes using the CopyTextfile and Madlib programs. Several text files, including some madlibs, are available under Labs/lab03. Try making a copy of each file with CopyTextfile and then verifying that the copy is identical to the original. On a Mac, you can check if two files are identical by running the diff command in a Terminal window, like this: diff file1.txt file2.txt The diff command will generate no output if the files are identical. Changing the Implementation Once you have debugged your code and are convinced that your ASCIIFileReader and ASCIIFileWriter classes are working correctly, run some timing tests on the CopyTextfile program in a Terminal window, as shown below: time java CopyTextfile bigmoby.txt bigmoby2.txt This will report the total amount of time taken to run the program. The file bigmoby.txt consists of five entire copies of Moby Dick concatenated together. Copying it will probably take a few seconds to complete. We can speed up the implementation of ASCIIFileReader by using a StringBuilder object in place of a String for the internal buffer. Read about StringBuilder in the Java API documentation (and on pages 885886 of your textbook), then make a copy of your ASCIIFileReader class definition, called ASCIIFileReader2, and change the representation of the buffer to a StringBuilder. You’ll need to modify your other methods accordingly, but because the implementation details of each method are hidden behind the “abstraction barrier” provided by the ASCIIFileReader interface, you do not need to modify your client programs (CopyTextfile and Madlib) at all, other than changing them to use the new ASCIIFileReader2 class in place of ASCIIFileReader. After making these changes and testing your new implementation, repeat the above timing test. Do you see any significant improvements in speed? The following StringBuilder methods will probably come in handy: setLength, replace, insert, charAt, and length.