520 likes | 641 Views
Object-Oriented Programming 95-712. MISM/MSIT Carnegie Mellon University Lecture 10: I/O, RTTI. Today’s Topics. The File class Using command line arguments More on the Java I/O classes The SimpleInput class, in detail Java’s compression classes (briefly)
E N D
Object-Oriented Programming95-712 MISM/MSIT Carnegie Mellon University Lecture 10: I/O, RTTI
Today’s Topics • The File class • Using command line arguments • More on the Java I/O classes • The SimpleInput class, in detail • Java’s compression classes (briefly) • Run-time type identification (RTTI) • A little on javadoc
The File Class • Think of this as holding a file name, or a list of file names (as in a directory). • You create one by giving the constructor a pathname, as in File f = new File(D:\Together5.02\myprojects\JavaCourse\Week9\DirList\.); • This is a directory, so now the Filef holds a list of (the names of) files in the directory. • It’s straightforward to print them out.
Listing Files import java.io.*; import java.util.*; public class DirList { public static void main(String[] args) { File path = new File("."); String[] list; System.out.println(path.getAbsolutePath()); if(args.length == 0) list = path.list(); else list = path.list(new DirFilter(args[0])); for (int i = 0; i < list.length; i++) System.out.println(list[i]); } }
With No Command Line Args… D:\Together5.02\myprojects\JavaCourse\Week9\DirList\. default.dfPackage default.dfPackage.wmf DirFilter.java DirList.java DirList.tpr DirList.tws
With “.java” on the Command Line D:\Together5.02\myprojects\JavaCourse\Week9\DirList\. DirFilter.java DirList.java
DirFilter is a FilenameFilter • Its only method is accept(): import java.io.*; import java.util.*; public class DirFilter implements FilenameFilter { String afn; DirFilter(String afn) { this.afn = afn; } public boolean accept(File dir, String name) { String f = new File(name).getName(); return f.indexOf(afn) != -1; } }
Using the “args” in main() • All this time we’ve been dumbly typing public static void main(String[] args) {… • args is an array of Strings, but for us it’s usually been empty. • It contains any command line parameters we choose to include. • If we’re at a DOS or Unix command line, we might type >java DirList .java • In Together, we set the Run Configuration
Other File Methods • canRead() • canWrite() • exists() • getParent() • isDirectory() • isFile() • lastModified() • length()
File Methods for Modifying • createNewFile() • delete() • makeDir() • makeDirs() • renameTo() • setLastModified() • setReadOnly()
More on Input All of these return bytes!
FilterInputStream JavaDoc • A FilterInputStream contains some other input stream, which it uses as its basic source of data, possibly transforming the data along the way or providing additional functionality. • The class FilterInputStream itself simply overrides all methods of InputStream with versions that pass all requests to the contained input stream. • Subclasses of FilterInputStream may further override some of these methods and may also provide additional methods and fields.
Readers These return chars!
We Saw These Last Time BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); InputStreamReader isr = new InputStreamReader(new FileInputStream("FileInput.java")); //slow: unbuffered This is easier (if we’re happy with the default character encoding and buffer size: InputStreamReader isr = new FileReader(" FileInput.java");
OutputStreams and Writers • Basically, a “mirror image” of InputStreams and Readers. • Wrapping is the same, e.g., BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); String s; try { while ((s = br.readLine()).length() != 0) { bw.write(s, 0, s.length()); bw.newLine(); bw.flush(); } }
FileWriter • Again, basically the same. The constructors are • FileWriter(File file) • FileWriter(FileDescriptor fd) • FileWriter(String s) • FileWriter(String s, boolean append) • The last one allows appending, rather than writing to the beginning (and erasing an existing file!). • These will create files! • There is also PrintWriter
PrintWriter PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("Test.txt"))); String s; try { while ((s = br.readLine()).length() != 0) { bw.write(s, 0, s.length()); bw.newLine(); bw.flush(); out.println(s); //out.flush(); } } catch(IOException e) { } out.close(); // also flushes
The SimpleInput Class • You’ve used this class (by David Barnes) a number of times, now let’s examine it. • The idea is to make it easy to open a file, and provide methods like • short nextShort() • double nextDouble() • …all the other primitive types • String nextWord() • String nextLine() • String getDelimiters() • void setDelimiters(String) • The “file” could be System.in.
SimpleInput (cont.) • This functionality is provided in C++ by the standard iostream library. Why something similar isn’t “stock” in Java mystifies me… • SimpleInput uses the StringTokenizer class • The StreamTokenizer class is similar, but with more features (and some drawbacks). • What’s a “token”? Any sequence of non-delimiter characters.
StringTokenizer Example StringTokenizer st = new StringTokenizer("this is a test"); while (st.hasMoreTokens()) { println(st.nextToken()); } This prints: this is a test The default delimiter string is " \t\n\r\f"
How Does It Work? Tokenizer initialized with a String: delimiters { \t\n\r\f} t h i s i s a t e s t Call nextToken(); search forward for next non-delimiter, and remember its position delimiters { \t\n\r\f} t h i s i s a t e s t (A very short search this time!)
How Does It Work (cont.) Search forward for next delimiter, and remember its position delimiters { \t\n\r\f} t h i s i s a t e s t Create and return the substring between these two positions. delimiters { \t\n\r\f} t h i s i s a t e s t t h i s
The Basic Plan • A StringTokenizer holds the current line. • Upon a request for a token: • if there are tokens remaining in the current line, try to convert the next token to the desired type, and return it • otherwise, skip and try to convert the next token • otherwise, read a new line, and try again • Upon a request for the next line: • discard the “left-over” line • read a new line and return it
Private Variables import java.io.*; import java.util.StringTokenizer; public class SimpleInput { private static final BufferedReader stdinReader = new BufferedReader(new InputStreamReader(System.in)); private BufferedReader reader = stdinReader; private String delimiters = " "; private StringTokenizer tokenizer = new StringTokenizer(""); }
Private Variables • This illustrates the way that Java implements “default values”. • A class simply initializes member variables to default values in its class declaration, and leaves it to a constructor to change the defaults as required. • This is equivalent to the C++ technique of default constructor arguments. • There are “set `n get” methods for these:
Private vs. Public Set `n Gets private BufferedReader getReader() { return reader; } private void setReader(BufferedReader r) { reader = r; } private StringTokenizer getTokenizer() { return tokenizer; } private void setTokenizer(StringTokenizer t) { tokenizer = t; } public String getDelimiters() { return delimiters; } public void setDelimiters(String d) { if ((d != null) && (d.length() > 0)) delimiters = d; }
SimpleInput Constructors public SimpleInput() { // uses standard input } public SimpleInput(String file) throws RuntimeException { File details = new File(file); if (!details.exists()) throw new RuntimeException(file + " does not exist."); else if (!details.canRead()) throw new RuntimeException(file + " exists but is unreadable."); else if (!details.isFile()) throw new RuntimeException(file + " is not a regular file."); else { try { setReader(new BufferedReader(new FileReader(details))); } catch (FileNotFoundException e) { throw new RuntimeException("Failed to open " + file + " for unknown reason."); } } }
getLine() (Note It’s public) public String nextLine() throws RuntimeException { try { discardLine(); BufferedReader reader = getReader(); String line = reader.readLine(); //if (line == null) // throw new RuntimeException("End of input."); return line; } catch (IOException e) { // pass it on as an unchecked exception throw new RuntimeException(e.getMessage()); } }
Is EOF An Exception? • Exceptions are things we don’t expect will ever happen. • But EOF happens for every file! • Is null an OK thing to return from getLine()? • Isn’t null just what a Reader returns? • Will this cause problems elsewhere?
Now nextToken() private String nextToken() throws RuntimeException { StringTokenizer t = getTokenizer(); final String delimiters = getDelimiters(); if (!t.hasMoreTokens()) { do { String line = nextLine(); //could throw exception t = new StringTokenizer(line, delimiters); setTokenizer(t); } while (!t.hasMoreTokens()); } return t.nextToken(delimiters); // could throw exception }
nextWord(), nextBoolean() public String nextWord() throws RuntimeException { return nextToken(); } public boolean nextBoolean() throws RuntimeException { for ( ; ; ) { String s = nextWord(); if (s.equalsIgnoreCase("t") || s.equalsIgnoreCase("true")) return true; else if (s.equalsIgnoreCase("f") || s.equalsIgnoreCase("false")) return false; } }
Where Are We? • So far, everything is in place to read lines and extract tokens. • An Exception structure is in place to report EOF. • The public methods so far are • nextLine() • nextWord() • nextBoolean() • Now some methods for numbers. • The plan: so long as we can find something recognizable as a double, cast it to the required type.
private double nextNumber() throws RuntimeException { Double number = null; // note this is Double, not double! do { String numString = null; try { numString = nextToken(); number = new Double(numString); } catch (NumberFormatException e) { numString = numString.toLowerCase(); numString = numString.replace('d', 'e'); try { number = new Double(numString); } catch (NumberFormatException ex) { // failed again } } } while (number == null); return number.doubleValue(); }
A Little About Double • The constructor used is Double(String s) • “Constructs a newly allocated Double object that represents the floating- point value of type double represented by the string. The string is converted to a double value as if by the valueOf method.” • See the description of valueOf() (it’s a bit complicated, but rest assured it tries hard!) • Acceptable Strings include 12, -1.34, -1.0e-10, etc.
These Two Are Natural public float nextFloat() throws RuntimeException { return (float)nextNumber(); } public double nextDouble() throws RuntimeException { return (double)nextNumber(); }
These Are Less Natural public short nextShort() throws RuntimeException { return (short)nextNumber(); } public int nextInt() throws RuntimeException { return (int)nextNumber(); } public long nextLong() throws RuntimeException { return (long)nextNumber(); }
SimpleInput: Summary • Some hard design decisions • Do everything possible to return the type asked for. • Use exceptions freely to make problems visible. • Are other choices possible? As always, yes! • Throwing exceptions from nextInt(), etc. seem reasonable, but EOF is a common occurrence. • Why not a hierarchy of specialized exceptions to make clearer just what has gone wrong?
Java’s Compression Classes • These are used to write and read streams in Zip and GZIP formats. • As always, these classes are wrappers around existing I/O classes, for “transparent” use. • These classes are astonishingly easy to use! • C++ should have this… • Here is a picture of the input classes (the output classes are similar):
Eckel’s GZIP Example (1st part) import java.io.*; import java.util.zip.*; public class GZIPCompress { public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader( new FileReader(args[0])); BufferedOutputStream out = new BufferedOutputStream( new GZIPOutputStream(new FileOutputStream("test.gz"))); System.out.println("Writing file"); int c; while((c = in.read()) != -1) out.write(c); in.close(); out.close();
GZIP Example (2nd part) System.out.println("Reading file"); BufferedReader in2 = new BufferedReader( new InputStreamReader( new GZIPInputStream( new FileInputStream("test.gz")))); // whew! String s; while((s = in2.readLine()) != null) System.out.println(s); } }
Comments • GZIP and Zip are specific algorithms for compressing and uncompressing. You’ll have to wait for details until Prof. McCarthy’s course. • This program works pretty well: • DancingMen.txt is 51KB • test.gz is 21KB
RTTI • We know this is possible, first, because of the Cats`n`Dogs example. • An ArrayList of Cats, with a Dog somehow placed in it. • Calling purr() for the Cats works, but not for the Dog: ClassCastException. • Second, we’ve seen this example:
Finding a Battery boolean takeAnAABattery() { Iterator i = contents.iterator(); Object aa = null; // initialize, or compiler complains while(i.hasNext()) { if ( (aa = i.next()) instanceof AABattery ) { contents.remove(aa); return true; } } return false; }
RTTI and Polymorphism class Shape {} class Circle extends Shape {public void draw(){}} class Square extends Shape {public void draw(){}} public class Shapes { public static void main(String[] args) { ArrayList s = new ArrayList(); s.add(new Circle()); s.add(new Square()); Iterator e = s.iterator(); while(e.hasNext()) ((Shape)e.next()).draw(); } }
Class Objects • Contain information about each of the classes in our program. • When we write and compile a class, say MyClass, the Class object for MyClass is generated. • When we use MyClass at runtime (by creating an object or calling a static method), the Class object is loaded, and it creates the new MyClass object. • The same Class object is used to make any other MyClass objects we require.
Using Class Objects • We can get a reference to a Class object: MyClass.class; • The Class class (whew!) has a number of useful methods: • Method[] getMethods() • Field[] getFields() • String getName() • boolean isArray() • boolean isInstance(Object) • Object newInstance()
newInstance() ArrayList s = new ArrayList(); Class[] shapes = {Circle.class, Square.class}; try { for (int i = 0; i < 10; i++) { int r = Random.nextInt(2); s.add(shapes[r].newInstance()); } } catch(InstantiationException e) {throw e;} catch(IllegalAccessException e) {throw e;} • An alternative to the clone method we used in genetic programming.
Run-Time Class Information • RTTI can give you the precise type of an object at run-time, but the existence of the type must be known at compile-time. • What if we get a bunch of bytes (over the Web, maybe) at runtime, and we’re told they represent a class. Can we use it? • Think of an application builder tool. • Think of business rules in middleware on a distant machine.