• echoes all the words in one file to an output file, one per line.
$ java Echo hamlet.txt hamlet.out
$ less hamlet.out
1604 the tragedy of hamlet prince of denmark by william shakespeare ...
import java.io.*; import java.util.StringTokenizer; public class Echo { public static void main( String[] args ) throws IOException {
String delimiters = " .?!()[]{}|?/&\\,;:-\'\"\t\n\r";
BufferedReader inputFile = new BufferedReader(new FileReader(args[0]) );
PrintWriter outputFile = new PrintWriter( new FileWriter( args[1] ) );
String buffer = null; while( true ) { buffer = inputFile.readLine(); if ( buffer == null ) break; buffer = buffer.toLowerCase();
StringTokenizer tokens = new StringTokenizer( buffer, delimiters ); while( tokens.hasMoreElements() ) {
String word = tokens.nextToken(); outputFile.println( word );
} // end while
} // end while(true)...
} // end main
} // end class Echo
• Sometimes, we'd like to give the user an option of providing a file name or using standard I/O.
• We can call sort with its own file argument, or we can pipe the standard output of one program (cat hamlet.out) as the standard input to sort.
• How can we make our Java programs do the same thing?
• a stream is a device for transmitting or receiving a sequence of byte (8-bit) values
– emphasis on reading/writing -- not on data itself
– network and file systems are based on byte unit
• Readers and Writers use 16-bit Unicode
– useful for I/O of textual values as opposed to binary data such as images, colors, etc.
– for example, BufferedRead has readLine method
• Standard input is an instance of the
InputStream class and does not respond to readLine(), which is how we would like to grab lines of text as Strings.
• Standard output does respond to println() messages, but it is a PrintStream, which cannot be stored in a PrintWriter variable.
• We could write duplicate code for the four different cases. (file-file, file-stdout, stdin-file, stdin-stdout)
• Every case would look the same except for one or two lines.
• That doesn't seem to be the correct solution.
•
Maybe we can find a way to have them talk to objects that talk to standard input and output...
• Let's take advantage of an object-oriented idea: We ought to be able to substitute an object with a common interface, even if somewhat different behavior, in place of one another, and let the new object fulfill the responsibilities of the replaced one.
• While BufferedReaders and PrintWriters don't know how to talk to standard input and output, respectively, we can use a translator to serve as a go-between.
• Java give us the classes we need: InputStreamReader and
OutputStreamWriter.
import java.io.*; import java.util.StringTokenizer; public class EchoStandard { public static void main( String[] args ) throws IOException {
String delimiters = " .?!()[]{}|?/&\\,;:-\'\"\t\n\r";
BufferedReader inputFile = new BufferedReader( new InputStreamReader( System.in ) );
PrintWriter outputFile = new PrintWriter( new OutputStreamWriter( System.out ) );
String buffer = null; while( true ) { buffer = inputFile.readLine(); if ( buffer == null ) break; buffer = buffer.toLowerCase();
StringTokenizer tokens = new StringTokenizer(buffer,delimiters); while( tokens.hasMoreElements() ) {
String word = tokens.nextToken(); outputFile.println( word );
} // end while
} // end while( true )...
} // end main
} // end class EchoStandard
BufferedReader inputFile = new BufferedReader( new FileReader( args[0]) );
PrintWriter outputFile = new PrintWriter( new FileWriter( args[1]) );
BufferedReader inputFile = new BufferedReader( new InputStreamReader( System.in ) );
PrintWriter outputFile = new PrintWriter( new OutputStreamWriter( System.out ) );
• Turn Echo.java into EchoV2.java, which behaves just like Echo, except that it takes two optional command-line arguments: the names of the input file and output file, respectively.
• If the user omits the second argument, the program writes to standard output.
• If the user omits both arguments, the program reads from standard output and writes to standard output. For example:
$ java EchoV2 hamlet.txt hamlet.out
$ less hamlet.out
1604 the tragedy of
...
$ java EchoV2 EchoV2.java
...
$ java EchoV2 hamlet.txt | less (interesting that the pipe “|” is not args[1])
1604 the tragedy of
...
$ java EchoV2
...
$ cat hamlet.txt | java EchoV2 | less
1604 the tragedy of
...
• Extend the MemoPad program so it can save and load memos to and from files
• You’ll need to add two responsibilities to the MemoDatabase interface:
– loading from a file
– saving to a file
• a new MemoPadApp.java that only creates instances
MyMemoDatabase. It accepts a single optional argument, the maximum size of the database.
java MemoPadApp // creates a default student database java MemoPadApp 100 // creates a database with up to 100 memos
• all of the graphics and management classes necessary to compile your application
• a jar file that will let you run a working program, to see how your program should work. Just use this command: java -jar memopad.jar // same as first example above java -jar memopad.jar 100 // same as second example above
• Change MemoPadApp.java to create instances of your MemoDatabase class.
– On Lines 8 and 10, MemoPadApp creates instances of a MemoDatabase for the
MemoPad. Put your class's name in place of my class's name. If you named your class
ArrayBasedMemoDatabase, you don't have to do anything!
• 2. Add empty save() and load() methods to your MemoDatabase class.
– This should ensure that your class now implements the extended MemoDatabase interface.
– Compile and run the program to verify this.
– Of course, the Save and Load buttons won't do anything yet
• Write the save() method for your class.
– This method takes a String argument, the name of the file to write. When the user presses the Save to File button, the MemoPad sends the database a save() message, with the current value of the Key: field as the filename.
– You get to decide the format of the data that your
MemoDatabase object writes to the file. For example, my program writes key/value pairs to a file in this format: eugene>>wallingford philip>>east
• Use your improved class to generate three to five data files.
– Compile the program and run it several times, each time saving a new file of memos. Name your files memos1.dat, memos2.dat, .... This will both enable you to verify that your method works and generate test data for the next task!
– Be sure that each file tests something different about your program. For example, it would be useful to have an empty file and at least one file with a large number of memos in it, to test the "boundary conditions" of the program.
• Write the load() method for your class.
– This method also takes as an argument the name of a file, taken from the current value of the Key: field.
– When the user presses the Load from File button, the MemoPad sends the database a load() message.
– This method should read records of the same format as the data written to file by the save() method.
• Use your new-and-improved class to read each of your data files.
– Compile the program and run it several times.
– Verify that your program can read each of the data files you created in Task 4.
– You should also be able to load multiple data files into the same memo pad. (*)
– Also verify that your program can load and save several times during the same execution.