Publicidad
Publicidad

Más contenido relacionado

Publicidad
Publicidad

Chap 9 : I/O and Streams (scjp/ocjp)

  1. I/O and Streams Ben Abdallah Helmi Architect 1
  2. Text, UTF, and Unicode • Programs may use UTF(UTF stands for UCS Transformation Format, and UCS in turn stands for Universal Character Set. to read and write Unicode. • Programs may use readers and writers to convert between internal Unicode and external8-bit encodings. Ben Abdallah Helmi Architect 2
  3. File Input and Output • Java’s java.io.File and java.io.RandomAccessFile classes provide functionality for navigating the local file system, describing files and directories, and accessing files in non-sequential order. (Accessing files sequentially is done with streams, readers, and writers, which are described later in this chapter.) All file access begins with the creation of an instance of one of these classes. • File(String pathname); • It is important to know that constructing an instance of File does not create a file on the local file system. Calling the constructor simply creates an instance that encapsulates the specified string. Ben Abdallah Helmi Architect 3
  4. There are two other versions of the File constructor: File(String dir, String subpath); File(File dir, String subpath); 1.File f1 = 2. new File(“/tmp”, “xyz”); // Assume /tmp is a dir 3. File f2 = new File(f1, “Xyz.java”); 1. File f1 = 2. new File(“C:a”); // Assume C:a is a dir 3. File f2 = new File(f1, “Xyz.java”); Eventually, if you try to access a file via a File instance that uses the wrong semantics, you’ll get a FileNotFoundException Ben Abdallah Helmi Architect 4
  5. The major methods that support navigation are as follows: • boolean exists() Returns true if the file or directory exists; otherwise returns false . • String getAbsolutePath() Returns the absolute (that is, not relative) path of the file or directory. • String getCanonicalPath() Returns the canonical path of the file or directory. This method is similar to getAbsolutePath() , but the symbols . And .. are resolved. • String getName() Returns the name of the file or directory. The name is the last element of the path. • String getParent() Returns the name of the directory that contains the File . • boolean isDirectory() Returns true if the File object describes a directory that exists on the file system. • boolean isFile() Returns true if the File object describes a file that exists on the file system. • String[] list() Returns an array containing the names of the files and directories within the File instance, which File must describe a Ben Abdallah Helmi Architect file. directory, not a 5
  6. Some non-navigation methods are as follows:canRead() Returns true if the file or directory may be • boolean • • • • • • read. boolean canWrite() Returns true if the file or directory may be modified. boolean createNewFile()Creates a new empty disk file as described by the current object, if such a file does not already exist. Returns true if the file was created. boolean delete() Attempts to delete the file or directory. long length() Returns the length of the file. boolean mkdir() Attempts to create a directory whose path is described by the current instance of File boolean renameTo(File newname ) Renames the file or directory. This method returns true if the renaming succeeded; otherwise it returns false . Ben Abdallah Helmi Architect 6
  7. here is a summary of the key points concerning the File class: • An instance of File describes a file or directory. • The file or directory might or might not exist. • Constructing/garbage collecting an instance of File has no effect on the local file system. Ben Abdallah Helmi Architect 7
  8. The RandomAccess File Class • This class presents a model of files that is incompatible with the stream/reader/writer model. • With a random-access file, you can seek to a desired position within a file and then read or write a desired amount of data. The RandomAccessFile class provides methods that support seeking, reading, and writing. Ben Abdallah Helmi Architect 8
  9. • The mode string should be either “r” or “rw”. Use “r” to open the file for reading only, and use “rw” to open for both reading and writing. In revision 5.0 two more modes were introduced: • “rws” and “rwd.” With a mode of “rws” the file is opened for reading and writing, and any changes to the file’s content or metadata take place immediately. (Metadata is all the data that describes a file: its permission modes, ownership, last-modified time, etc.) With the “rwd” mode, the file is opened for reading and writing, and changes to the files content, but not its metadata, take place immediately. Ben Abdallah Helmi Architect 9
  10. 1. File file = new File(path); 2. if (!file.isFile() || 3. !file.canRead() || 4. !file.canWrite()) 5. throw new IOException(); 6. RandomAccessFile raf = new RandomAccessFile(file, “rw”); • When the named file does not exist, constructing a RandomAccessFile is different from constructing an ordinary File. In this situation, if the random-access file is constructed in read-only mode, a FileNotFoundException is thrown. If the random-access file is constructed in readwrite mode, then a zero-length file is created. • Java’s random-access files support only seeking relative to the beginning of the file but methods exist that report the current position and the length of the file, so you can effectively perform the other kinds of seeking as long as you are willing to do the arithmetic. Ben Abdallah Helmi Architect 10
  11. The methods that support seeking are as follows: • long getFilePointer() throws IOException Returns the current position within the file, in bytes. Subsequent reading and writing will take place starting at this position. • long length() throws IOException Returns the length of the file, in bytes. • void seek(long position) throws IOException Sets the current position within the file, in bytes. Subsequent reading and writing will take place starting at this position. Files start at position 0. Ben Abdallah Helmi Architect 11
  12. import java.io.*; class GeneralRAF extends RandomAccessFile { public GeneralRAF(File path, String mode) throws IOException { super(path, mode); } public GeneralRAF(String path, String mode) throws IOException { super(path, mode); } public void seekFromEnd(long offset) throws IOException { seek(length() - offset); } public void seekFromCurrent(long offset) throws IOException { seek(getFilePointer() + offset); }} Ben Abdallah Helmi Architect 12
  13. int read() throws IOException Returns the next byte from the file (stored in the low-order eight bits of an int) or -1 if at the end of the file. int read(byte dest[]) throws IOException Attempts to read enough bytes to fill array dest[]. It returns the number of bytes read, or -1 if at the end of the file. int read(byte dest[], int offset, int len) throws IOException Attempts to read len bytes into array dest[], starting at offset. It returns the number of bytes read, or -1 if at the end of the file. void write(int b) throws IOException Writes the low-order byte of b. void write(byte b[]) throws IOException Writes all of byte array b[]. void write(byte b[], int offset, int len) throws IOException Writes len bytes from byte array b[], starting at offset. When a random-access file is no longer needed, it should be closed: void close() throws IOException Ben Abdallah Helmi Architect 13
  14. To summarize, random-access files offer the following functionality: • Seeking to any position within a file • Reading and writing single or multiple bytes • Reading and writing groups of bytes, treated as higherlevel data types • Closing Ben Abdallah Helmi Architect 14
  15. Streams, Readers, and Writers • Java’s stream, reader, and writer classes view input and output as ordered sequences of bytes. • You have already seen how the RandomAccessFile class allows you to read and write all of Java’s primitive data types. The readInt() method, for example, reads four bytes from a file, pieces them together, and returns an int. Java’s general I/O classes provide a similar structured approach. • The stream, reader, and writer classes are not very complicated. The easiest way to review them is to begin with the low-level streams. Ben Abdallah Helmi Architect 15
  16. Low-Level Streams • • • • • • • • • The two most common file input stream constructors are FileInputStream(String pathname) FileInputStream(File file) int read() throws IOException Returns the next byte from the file (stored in the low-order eight bits of an int) or -1 if at the end of the file. int read(byte dest[]) throws IOException Attempts to read enough bytes to fill array dest[]. It returns the number of bytes read or -1 if at the end of the file. int read(byte dest[], int offset, int len) throws IOException Attempts to read len bytes into array dest[], starting at offset. It returns the number of bytes read or -1 if at the end of the file int available() throws IOException Returns the number of bytes that can be read without blocking. void close() throws IOException Releases non-memory system resources associated with the file. A file input stream should always be closed when no longer needed. long s k ip(long n b y tes) throws IOException Attempts to read and discard nbytes bytes. Returns the number of bytes actually skipped. Ben Abdallah Helmi Architect 16
  17. byte b; byte bytes[] = new byte[100]; byte morebytes[] = new byte[50]; try { FileInputStream fis = new FileInputStream(“fname”); b = (byte) fis.read(); // Single byte fis.read(bytes); // Fill the array fis.read(morebytes, 0, 20); // 1st 20 elements fis.close(); } catch (IOException e) {} Ben Abdallah Helmi Architect 17
  18. • FileOutputStream(String pathname) • FileOutputStream(File file) • void write(int b) throws IOException Writes the low-order byte of b. • void write(byte bytes[]) throws IOException Writes all members of byte array bytes[]. • void write(byte bytes[], int offset, int len) throws IOException Writes len bytes from array bytes[], starting at offset. Ben Abdallah Helmi Architect 18
  19. In addition to the two classes described earlier, the java.io pack age has other low-level input and output stream classes: • InputStream and OutputStream These are the superclasses of the other low-level stream classes. They can be used for reading and writing network sockets. • ByteArrayInputStream and ByteArrayOutputStream These classes read and write arrays of bytes. Byte arrays are certainly not hardware I/O devices, but the classes are useful when you want to process or create sequences of bytes. • PipedInputStream and PipedOutputStream These classes provide a mechanism for synchronized communication between threads. Ben Abdallah Helmi Architect 19
  20. High-Level Streams java supports high-level I/O with high-level streams. The most common of extend from the superclasses FilterInputStream and FilterOutputStream. High-le vel inp ut streams do not re a d from inpu t devices s uch a s files or sockets; rather, they read from other streams. H i gh-level outpu t streams do not write to output devices but to other streams. A good example of a high-level input stream is the data input stream. This class has only one constructor: D ataInputStream(InputStream instream) The constructor requires you to pass in an input stream. This instance might be a file input stream (because FileInputStream extends InputStream), an input stream Ben Abdallah Helmi Architect 20
  21. The commonly used input methods of the DataInputStream class are as follows: boolean read Boolean() throws IOException byte read Byte() throws IOException char readChar () throws IOException double read Double () throws IOException float readFloat () throws IOException int readInt() throws IOException long readLong() throws IOException short readShort() throws IOException String read UTF() throws IOException There is, of course, a close() method. Ben Abdallah Helmi Architect 21
  22. try { // Construct the chain FileInputStream fis = new FileInputStream(“fname”); DataInputStream dis = new DataInputStream(fis); // R ead double d = dis.readDouble(); int i = dis.readInt(); String s = dis.readUTF(); // Close the chain dis.close(); // Close dis first, because it fis.close(); // was created last } catch (IOException e) { } Ben Abdallah Helmi Architect 22
  23. • The DataOutputStream class is the mirror image of the DataInputStream class. The constructor is DataOutputStream(OutputStream ostream). • The constructor requires you to pass in an output stream. When you write to the data output stream, it converts the parameters of the write methods to bytes and writes them to ostream. Ben Abdallah Helmi Architect 23
  24. The commonly used output methods of the DataOutputStream class are as follows: void write Boolean(boolean b) throws Exception void write Byte(int b) throws Exception void write Bytes(String s) throws Exception void writeChar(int c) throws Exception void write D ouble(double d) throws Exception void writeFloat(float b) throws Exception void writeInt(int i) throws Exception void writeLong(long l) throws Exception void writeShort(int s) throws Exception void writeUTF(String s) throws Exception Ben Abdallah Helmi Architect 24
  25. Ben Abdallah Helmi Architect 25
  26. try { // Create the chain FileOutputStream fos = new FileOutputStream(“txt”); DataOutputStream dos = new DataOutputStream(fos); // W rite dos.write D ouble(123.456); dos.writeInt(55); dos.writeUTF(“The moving finger writes”); // Close the chain dos.close(); fos.close(); } catch (IOException e) { } Ben Abdallah Helmi Architect 26
  27. • BufferedInputStream and B ufferedOutputStream These classes have internal buffers so that bytes can be read or written in large blocks, thus minimizing I/O overhead. • PrintStream This class can be asked to write text or primitives. Primitives are converted to character representations. The System.out and System.err objects are examples of this class. The class has a println() method that outputs a string followed by a newline character. It also has a format() method that prints formatted text. Text formatting is covered in Chapter 8, “The java.lang and java.util packages.” • PushbackInputStream This class allows the most recently read byte to be put back into the stream, as if it had not yet been read. This functionality is very useful for certain kinds of parsers. Ben Abdallah Helmi Architect 27
  28. • It is possible to create stream chains of arbitrary length. For example, the following code fragment implements a data input stream that reads from a buffered input stream, which in turn reads from a file input stream: • FileInputStream f = new FileInputStream(“text”); • BufferedInputStream b = new BufferedInputStream(f); • DataInputStream d = new DataInputStream(b); Ben Abdallah Helmi Architect 28
  29. Ben Abdallah Helmi Architect 29
  30. Readers and Writers • Readers and writers are like input and output streams: The low-level varieties communicate with I/O devices, and the high-level varieties communicate with low-level varieties. What makes readers and writers different is that they are exclusively oriented to Unicode characters. The other low-level reader and writer classes are as follows: • CharArrayReader and CharArrayWriter Read and write char arrays. • PipedReader and PipedWriter Provide a mechanism for thread communication. • StringReader and StringWriter Read and write strings. Ben Abdallah Helmi Architect 30
  31. • int read() throws IOException Returns the next char (stored in the low-order 16 bits of the int return value) or -1 if at the end of input. • int read(char dest[]) throws IOException Attempts to read enough chars to fill array dest[]. It returns the number of chars read or -1 if at the end of input. • int read(char dest[], int offset, int len) throws IOException Attempts to read len chars into array dest[], starting at offset. It returns the number of chars read or -1 if at the end of input Ben Abdallah Helmi Architect 31
  32. • int read() throws IOException Returns the next char (stored in the low-order 16 bits of the int return value) or -1 if at the end of input. • int read(char dest[]) throws IOException Attempts to read enough chars to fill array dest[]. It returns the number of chars read or -1 if at the end of input. • int read(char dest[], int offset, int len) throws IOException Attempts to read len chars into array dest[], starting at offset. It returns the number of chars read or -1 if at the end of input • LineNumberReader This class views its input as a sequence of lines of text. A method called readLine() returns the next line, and the class keeps track of the current line number. • PrintWriter This class is similar to PrintStream, but it writes chars rather than bytes. • PushbackReader This class is similar to PushbackInputStream, but it reads chars rather than bytes. Ben Abdallah Helmi Architect 32
  33. 1. try { 2. FileReader fr = new FileReader(“data”); 3. LineNumberReader lnr = new LineNumberReader(fr); 4. String s; 5. 6. while ((s = lnr.readLine()) != null) { 7. System.out.println(lnr.getLineNumber() + 8. “ : “ + s); 9. } 10. lnr.close(); 11. fr.close(); 12. } 13. catch (IOException x) { } Ben Abdallah Helmi Architect 33
  34. Ben Abdallah Helmi Architect 34
  35. • The preceding discussion has carefully avoided a crucial point. Consider a file reader, which reads bytes from a file and returns strings of Unicode. How does the reader know how to translate an 8-bit character on the disk into a 16-bit character inside the JVM? Similarly, how does a file writer know how to translate a 16-bit Unicode character into an 8-bit byte? • An encoding is a mapping between 8-bit characters and Unicode. Ben Abdallah Helmi Architect 35
  36. Object Streams and Serialization • As you have seen, data input and output streams allow you to read and write primitives and strings, rather than individual bytes. Object streams go one step beyond data streams by allowing you to read and write entire objects. • The process of writing an object is called serialization. To serialize an object, first create an instance of java.io.ObjectOutputStream. Ben Abdallah Helmi Architect 36
  37. void writeStringBuffer(StringBuffer writeMe) throws IOException { FileOutputStream fos = new FileOutputStrem(“sbuf.ser”); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(writeMe); oos.close(); fos.close(); } Ben Abdallah Helmi Architect StringBuffer readStringBuffer() throws IOException, ClassNotFoundExce ption { FileInputStream fis = new FileInputStream (“sbuf.ser”); ObjectInputStream ois = new ObjectInputStream(fis); StringBuffer sb = (StringBuffer)ois.readObject(); ois.close(); fis.close(); return sb; } 37
  38. • The ObjectOutputStream class has a writeUTF() method, as well as writeByte(), writeShort(), and all other write-primitive methods that also appear in data output streams. • The ObjectInputStream class has corresponding reading methods. So if you want to create a file that contains serialized primitives and strings as well as serialized objects, you can do it with a single output stream. • Static fields are not, because it would not be appropriate to change a static variable, which is shared by all instances of a class, just because one instance of the class got deserialized. (To deserialize is to convert a serialized representation into a replica of the original object.) Transient fields are also not serialized. • All non-static non-transient fields are written to object output streams,regardless of whether they are public, private, default, or protected. Ben Abdallah Helmi Architect 38
  39. • When an object is serialized, it will probably be deserialized by a different JVM. Any JVM that tries to deserialize an object must have access to that object’s class definition. In other words, if the class is not already loaded, its class file must appear in the new JVM’s classpath. If this is not the case, readObject() will throw an exception. • In the terminology of serialization, when an object is serialized, its entire graph is serialized. An object’s graph is the object itself, plus all the objects it references, plus all the objects those objects reference, and so on. When an object input stream deserializes an object, the entire graph is deserialized. Ben Abdallah Helmi Architect 39
  40. • public void writeObject(Object obj) • However, if you look at the method detail section for writeObject(), you’ll see that it throws NotSerializableException if “some object to be serialized does not implement the java.io.Serializable interface.” So even though the method declares that its argument is an object, it contains code that checks for the precondition that the argument must be an instanceof Serializable, and it throws the exception if the precondition is not met. Even if the object being passed into the method implements Serializable, the exception might still be thrown. Since the object’s entire graph is serialized, all objects referenced by the object must implement Serializable, and all objects referenced by those objects must do the same, and so on. Ben Abdallah Helmi Architect 40
  41. • You probably recognize the Serializable interface from your reading of the API pages. Most of the core Java classes implement it. All the wrapper classes do so, and so do the collection classes. In fact, the only core Java classes that do not implement Serializable are like Threads • Empty interfaces such as Serializable are known as tagging interfaces. They identify implementing classes as having certain properties, without requiring those classes to actually implement any methods. • Arrays of primitives or serializable objects are themselves serializable. That should not be serialized Ben Abdallah Helmi Architect 41
  42. • Deserializing involves a lot of tricky business behind the scenes. The object input stream creates a blank instance of the object being deserialized and then sets its field values. In order for this to happen, a bizarre condition must apply. Think about the class hierarchy of the object being deserialized. • The object itself implements Serializable; the object’s parent class might or might not implement Serializable. As you work your way up the inheritance hierarchy, you eventually get to the first superclass that is not itself serializable. That superclass must have a no-args constructor. • Often the first non-serializable superclass is Object, which does have the right kind of constructor. If the condition isn’t met, readObject() throws java.io.InvalidClassException. The exception message says, “no valid constructor.” Ben Abdallah Helmi Architect 42
  43. • Notice the private access. When an object output stream executes its writeObject() method, it checks to see if the object has a writeObject() method matching the above signature. If this is the case, the stream bypasses its default behavior (which is to serialize the object’s nonstatic non-transient fields) and just calls the object’s writeObject() method. • Similarly, when an object input stream executes its readObject() method, it checks to see if the object has a readObject() method matching the above signature, and if so the ordinary deserialization process is bypassed in favor of a call to the readObject() method. Ben Abdallah Helmi Architect 43
  44. • If a class wants its writeObject() method to take special action in addition to, rather than instead of, the default serialization behavior, it can call the output stream’s defaultWriteObject() method, which serializes the object’s non-static non-transient fields. • As you might expect, the ObjectInputStream class has a defaultReadObject() method, which deserializes the current object from the object input stream. Ben Abdallah Helmi Architect 44
  45. Import java.io.*; class DoItMyself implements Serializable { private String id; protected int n; transient byte notMe; private void writeObject(ObjectOutputStream oos) throws IOException { oos.writeUTF(“The password is swordfish”); oos.defaultWriteObject(); } private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { String password = ois.readUTF(); if (!password.equals(“The password is swordfish”)) throw new SecurityException(“Bad password”); ois.defaultReadObject(); Ben}}Abdallah Helmi Architect When an instance of this class is serialized, the object output stream notices that the instance has a writeObject() method with the appropriate signature. This method is called. A password string is serialized. Then the output stream’s defaultWriteObject() is called, and default serialization is performed. 45
  46. Another way to provide custom serialization and deserialization is to implement a subinterface of Serializable, called Externalizable. (Notice that since Externalizable extends Serializable, the implements Serializable precondition in writeObject() is met by any object that implements Externalizable. Externalizable contains two method signatures: void writeExternal(ObjectOutput out) throws IOException void readExternal(ObjectInput in) throws IOException, ClassNotFoundException • ObjectOutput and ObjectInput are interfaces that are implemented by ObjectOutputStream and ObjectInputStream. They define, respectively, writeObject() and readObject() methods Ben Abdallah Helmi Architect 46
  47. import java.io.*; public class Account implements Externalizable { private String ownerName; private String password; private float balance; private String reverse(String reverseMe) { String reversed = ""; for (int i=reverseMe.length()-1; i>=0; i--) reversed += reverseMe.charAt(i); return reversed; } public void writeExternal(ObjectOutput outStream) throws IOException { outStream.writeObject(ownerName); outStream.writeObject(reverse(password)); When an instance of this class is passed to an object output stream, the default serialization procedure is bypassed; instead, the stream calls the instance’s writeExternal() method. When an object input stream reads a serialized instance of Account, a call is made to the no-args constructor for the Account class; this constructor must be public. Then the newly constructed object receives a readExternal() call so that it can reconstitute its serialized values. outStream.writeObject(new Float(balance)); } public void readExternal(ObjectInput inStream) throws IOException, ClassNotFoundException { ownerName = (String)inStream.readObject(); String reversedPassword = (String)inStream.readObject(); password = reverse(reversedPassword); balance = ((Float)inStream.readObject()).floatValue(); Ben Abdallah Helmi Architect }} 47
  48. • Notice that the readObject() mechanism of ObjectInputStream relies on the existence of a no-args constructor for any class that implements Externalizable. If an externalizable class has no no-args constructor, the readObject() method will throw java.io.InvalidClassException. Ben Abdallah Helmi Architect 48
Publicidad