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
Java I/O L. Grewe Overview of java.io methods for accessing file, text data, object serialization and internationalization Sequential and Random access Reading and writing of primitive values Applications and applets are provided with three streams automatically System.out (output stream) System.in (input stream) System.err (error stream Uses Streams Two kinds of basic streams: 1. byte based streams 2. 8 bits, data-based input streams and output streams character based streams 16 bits, text-based readers and writers Byte Streams Two parent abstract classes: InputStream and OutputStream Reading bytes: • InputStream class defines an abstract method public abstract int read() throws IOException Designer of a concrete input stream class overrides this method to provide useful functionality. E.g. in the FileInputStream class, the method reads one byte from a file • InputStream class also contains nonabstract methods to read an array of bytes or skip a number of bytes Writing bytes: • OutputStream class defines an abstract method public abstract void write(int b) throws IOException • OutputStream class also contains nonabstract methods for tasks such as writing bytes from a specified byte array Close the stream after reading of writing to it to free up limited operating system resources by using close() Byte Streams (Binary Streams)…some of the hierarchy FileInputStream InputStream BufferedInputStream FilterInputStream DataInputStream Object FileOutputStream BufferedOutputStream OutputStream FilterOutputStream DataOutputStream PrintStream Byte Stream some of the hierarchy AutioInputStream FileInputStream InputStream ObjectInputStream SequenceInputStream ByteArrayInputStream PipedInputStream FilterInputStream Byte Streams FileOutputStream ObjectOutputStream OutputStream ByteArrayOutputStream PipeOutputStream FilterOutputStream Java Programming Byte Streams import java.io.*; The abstract class InputStream declares methods to read bytes from a particular source. public class CountBytes { public static void main(String[] args) Type is InputStream throws IOException { InputStream in; Reads a single byte of data and returns if (args.length == 0) the byte that was read, as an integer in the range 0 to 255, not -128 to in = System.in; 127(unsigned). else in = new FileInputStream(args[0]); } } int total = 0; while (in.read() != -1) total++; System.out.println(total + " bytes"); Example code1: import java.io.*; class CountBytes { public static void main(String[] args) throws IOException { FileInputStream in = new FileInputStream(args[0]); int total = 0; while (in.read() != -1) total++; in.close(); System.out.println(total + ” bytes”); } } Example code2: import java.io.*; class TranslateByte { public static void main(String[] args) throws IOException { byte from = (byte)args[0].charAt(0); byte to = (byte)args[1].charAt(0); int x; while((x = System.in.read()) != -1) System.out.write(x == from ? to : x); } } If you run “java TranslateByte b B” and enter text bigboy via the keyboard the output will be: BigBoy! Byte Stream - output Byte Stream - Output import java.io.*; The abstract class OutputStream provides an abstraction for writing bytes to a destination. public class TranslateByte { public static void main(String[] args) throws IOException { byte from = (byte) args[0].charAt(0); byte to = (byte) args[1].charAt(0); int b; while ((b = System.in.read()) != -1) System.out.write(b == from ? to : b); } Run: } Type is PrintStream Java TranslateByte b B Result: (input abracadabra!) aBracadaBra! Character streams Two parent abstract classes for characters: Reader and Writer. Each support similar methods to those of its byte stream counterpart–InputStream and OutputStream, respectively The standard streams—System.in, System.out and System.err—existed before the invention of character streams. So they are byte streams though logically they should be character streams. Character Streams - Reading BufferedReader InputStreamReader Reader StringReader CharArrayReader PipedReader FilterReader Character Streams - Writing BufferedWriter OutputStreamWriter Writer StringWriter CharArrayWriter PipedWriter FilterWriter PrintWriter Conversion between byte and character streams The conversion streams InputStreamReader and OutputStreamReader translate between Character and byte streams • • • • public InputStreamReader(InputStream in) public InputStreamReader(InputStream in, String encoding) public OutputStreamWriter(OutputStream out) public OutputStreamWriter(OutputStream out, String encoding) read method of InputStreamReader read bytes from their associated InputStream and convert them to characters using the appropriate encoding for that stream write method of OutputStreamWriter take the supplied characters, convert them to bytes using the appropriate encoding and write them to its associated OutputStream Closing the conversion stream also closes the associated byte stream – may not always desirable Character Stream Example import java.io.*; The abstract classes for reading and writing streams of characters are Reader and Writer. public class CountSpace { The abstract class Reader provides a public static void main(String[] args) character stream analogous to the byte throws IOException stream InputStream and the methods of { Reader essentially mirror those of Reader in; InputStream. if (args.length == 0) in = new InputStreamReader(System.in); else Run: in = new FileReader(args[0]); Java CountSpace CountSpace.java Result: } } int ch; 520 characters 172 spaces int total; int spaces = 0; for (total = 0; (ch = in.read()) != -1; total++) { if (Character.isWhitespace((char) ch)) spaces++; } The conversion streams System.out.println(total + " chars " InputStreamReader and + spaces + " spaces"); OutputStreamWriter translate between character and byte streams using either a specified character set encoding or the default encoding for the local system. Reading from a Stream The basic read() method reads a byte at a time. Some other methods that read more than 1 byte • public int read(byte[] data) throws IOException Tries to read enough bytes to fill the array data • public int read(byte[] data, int offset, int length) throws IOException Tries to read length bytes from stream and store in data[] at starting index offset • These methods then return the number of bytes actually read. You should not assume that the array will be filled or that length bytes will actually have been read. If the end of stream is encountered, -1 is returned Reading Use other classes with richer methods (i.e. DataInputStream) to read in different data types Writing abstract void write(char[] cbuf, int off, int len) Write a portion of an array of characters. void write(int c) Write a single character. voidwrite(String str) Write a string. voidwrite(String str, int off, int len) Write a portion of a string. Other methods – for byte based – print*(*) abstract void close() Close the stream, flushing it abstract void flush() Flush the stream. voidwrite(char[] cbuf) Write an array of characters. File I/O : The File class The File class is particularly useful for retrieving information about a file or a directory from a disk. • A File object actually represents a path, not necessarily an underlying file • A File object doesn’t open files or provide any file-processing capabilities Three constructors • • • public File( String name) public File( String pathToName, String name) public File( File directory, String name) Main methods • boolean canRead() / boolean canWrite() • boolean exists() • boolean isFile() / boolean isDirectory() / boolean isAbsolute() • String getAbsolutePath() / String getPath() • String getParent() • String getName() • long length() • long lastModified() File I/O Sequential-Access file: the File streams— FileInputStream, FileOutputStream, FileReader and FileWriter—allow you to treat a file as a stream to input or output sequentially • Each file stream type has three types of constructors A constructor that takes a String which is the name of the file A constructor that take a File object which refers to the file A constructor that takes a FileDescriptor object Random-Access file: RandomAccessFile allow you to read/write data beginning at the a specified location • a file pointer is used to guide the starting position • It’s not a subclass of InputStream, OutputStream, Reader or Writer because it supports both input and output with both bytes and characters Example of RandomAccessFile import java.io.*; class Filecopy { public static void main(String args[]) { RandomAccessFile fh1 = null; RandomAccessFile fh2 = null; long filesize = -1; byte[] buffer1; try { fh1 = new RandomAccessFile(args[0], “r”); fh2 = new RandomAccessFile(args[1], “rw”); } catch (FileNotFoundException e) { System.out.println(“File not found”); System.exit(100); } try { filesize = fh1.length(); int bufsize = (int)filesize/2; buffer1 = new byte[bufsize]; fh1.readFully(buffer1, 0, bufsize); fh2.write(buffer1, 0, bufsize); } catch (IOException e) { System.out.println("IO error occurred!"); System.exit(200); } } } Add more efficiency BufferedReader reads text from a character-input stream, buffering characters so as to provide for the efficient reading of characters, arrays, and lines. BufferedReader (Reader in) For example: to wrap an InputStreamReader inside a BufferedReader BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); to wrap a FileReader inside a BufferedReader BufferedReader in = new BufferedReader(new FileReader(“fileName”)); then you can invoke in.readLine() to read from the file line by line import java.io.*; public class EfficientReader { public static void main (String[] args) { try { BufferedReader br = new BufferedReader(new FileReader(args[0])); // get line String line = br.readLine(); } } // while not end of file… keep reading and displaying lines while (line != null) { System.out.println("Read a line:"); System.out.println(line); line = br.readLine(); } // close stream br.close(); } catch(FileNotFoundException fe) { System.out.println("File not found: “+ args[0]"); } catch(IOException ioe) { System.out.println("Can’t read from file: “+args[0]); } Buffering Improves performance of I/O Copies each output to a region of memory called a buffer Entire buffer output to disk at once One long disk access takes less time than many smaller ones • • BufferedInputStream buffers file output BufferedOutputStream buffers file input Appending to a File To append to file instead of overwriting it pass the boolean value true as the second argument to the FileOutputStream() constructor. For example, FileOutputStream fos = new FileOutputStream(“File.txt", true); More on Writing to a File The java.io.FileWriter class writes text files using the platform's default character encoding and the buffer size. If you need to change these values, construct an OutputStreamReader on a FileOutputStream instead. LineNumberReader class The java.io.LineNumberReader class is a subclass of java.io.BufferedReader that keeps track of which line you're currently reading. It has all the methods of BufferedReader including readLine(). It also has two constructors, getLineNumber(), and setLineNumber() methods: • • • • public public public public LineNumberReader(Reader in) LineNumberReader(Reader in, int size) int getLineNumber() void setLineNumber(int lineNumber) The setLineNumber() method does not change the file pointer. It just changes the value getLineNumber() returns. For example, it would allow you to start counting from -5 if you knew there were six lines of header data you didn't want to count. Lets look at some examples First ---- using DataInputStream and DataOutputStream Data Input/Output Stream example OUTPUT 256 3.141592653589793 Jav import java.io.*; class DOSDISDemo { public static void main (String [] args) { DataOutputStream dos = null; DataInputStream dis = null; try { FileInputStream fis = new FileInputStream ("data.dat"); dis = new DataInputStream (fis); try { FileOutputStream fos = new FileOutputStream ("data.dat"); dos = new DataOutputStream (fos); System.out.println (dis.readInt ()); System.out.println (dis.readDouble ()); System.out.println (dis.readUTF ()); } catch (IOException e) { System.out.println (e.getMessage ()); return; } finally { if (dis != null) try { dis.close (); } catch (IOException e) { } } dos.writeInt (256); dos.writeDouble (Math.PI); dos.writeUTF ("Java"); } catch (IOException e) { System.out.println (e.getMessage ()); return; } finally { if (dos != null) try { dos.close (); } catch (IOException e) { } } } } Another Example--- Piped Streams A Motivation? •Threads are often required to communicate. •Can use piped streams. •IDEA= connect a piped output stream to a piped input stream. •Then, one thread writes data to the piped output stream and another thread reads that data by way of the piped input stream. •CAUTION= streams have limited sizes. As a result, a writing thread could write more output to a piped output stream than that stream can accommodate, and the excess output would be lost. To prevent that from happening, the reading thread must be responsive. Buffered Streams, Piped Streams (here with same thread) Character Stream import java.io.*; public class BufferedReaderTest { public static void main(String[] args) throws IOException { InputStream BufferedReader charStream = new BufferedReader (new InputStreamReader(System.in)); String data = charStream.readLine(); // Read a line from standard input } } System.out.println("Input = " + data); The Buffered stream classes buffer their data to avoid every read or write going directly to the next stream. These classes are often used in conjunction with File streams. import java.io.*; class TextGenerator extends Thread { private Writer out; public TextGenerator(Writer out) { this.out = out; } public void run() { try { try { for (char c = 'a'; c <= 'z'; c++) out.write(c); } finally { out.close(); } } catch(IOException e) { } getUncaughtExceptionHandler().uncaughtExcepti on(this, e); } } public class Pipe { public static void main(String[] args) throws IOException { PipedWriter out = new PipedWriter(); PipedReader in = new PipedReader(out); TextGenerator data = new TextGenerator(out); data.start(); int ch; while ((ch=in.read()) != -1) System.out.print((char) ch); System.out.println(); } Result: } abcdefghijklmnopqrstuvwxyz Another Example--LineNumberReader Tracks Line numbers as you are reading Print Streams, LineNumberReader The Print streams provide methods that make it easy to write the values of primitive types and object to a stream, in a human-readable text format • print and println method The call out.print(f) is equivalent to out.write(String.valueOf(f).getByt es()); import java.io.*; public class FindChar { public static void main(String[] args) throws IOException { if (args.length != 2) throw new IllegalArgumentException( "need char and file"); LineNumberReader The LineNumberReader stream keeps track of line numbers while reading text. Run: %java FindChar I FindChar.java Result: ‘I’ at line 4 } } int match = args[0].charAt(0); FileReader fileIn = new FileReader(args[1]); LineNumberReader in = new LineNumberReader(fileIn); int ch; while ((ch = in.read()) != -1) { if (ch == match) { System.out.println("'" + (char) ch + "' at line " + in.getLineNumber()); return ; } } System.out.println((char) match + " not found"); Another Example …Pushback Streams Pushback is used on an input stream to allow a byte to be read and then returned(that is "pushed back") to the stream. PushbackInputStream provides a mechanism to "peek " at what is coming from an input stream without disrupting it. Pushback Streams A Pushback stream lets you push back, or “unread” characters or bytes when you have read too far. Pushback is typically useful for breaking input into tokens. For example, lexical scanners often know that a token (such as an identifier) has ended only when they have read the first character that follows it. The following example uses PushbackInputStream to report the longest consecutive sequence of any single byte in its input: Run and Result: % java SequenceCount 12345111 ^D in Unix(or ^Z in Windows) 3 bytes of 49 import java.io.*; public class SequenceCount { public static void main(String[] args) throws IOException { PushbackInputStream in = new PushbackInputStream(System.in); int max = 0; // longest sequence found int maxB = -1; // the byte in that sequence int b; // current byte in input } } do { int cnt; int b1 = in.read(); for (cnt = 1; (b = in.read()) == b1; cnt++) continue; if (cnt > max) { max = cnt; // remember length maxB = b1; // remember which byte value } in.unread(b); // pushback start of ntext seq } while (b != -1); // until we hit end of input System.out.println(max + " byte of " + maxB); Another Example Java I/O even has ability to read zip files java.util.zip • ZipInputStream ,ZipOutputStream Zip File Example –will list contents // ZipReader.java import java.io.*; import java.util.zip.*; class ZipReader { public static void main (String [] args) { if (args.length != 1) { System.out.println ("usage: java ZipReader pathname"); return; } ZipInputStream zis = null; try { FileInputStream fis = new FileInputStream (args [0]); zis = new ZipInputStream (fis); ZipEntry ze; while ((ze = zis.getNextEntry ()) != null) System.out.println (ze.getName ()); } // ZipReader.java catch (IOException e) { System.out.println (e.getMessage ()); } finally { try { zis.close (); } catch (IOException e) { } } } } To run ZipReader, you need access to either a Zip file or a Jar file (which is basically a Zip file with a .jar extension A useful class in I/O –the StreamTokenizer The StreamTokenizer gives simple tokenization. More general facility for scanning and converting input text is provided by the java.util.Scanner class. StreamTokenzier Four token type • TT_WORD • TT_NUMBER • TT_EOL • TT_EOF Result Input (tokens.txt) The price is $23.45. Is that too expensive? (I don’t think so.) Run: java StreamTokenizerDemo tokens.txt 1) 1) 1) 1) 1) 1) 2) 2) 2) 2) 2) 3) 3) 3) 3) 3) 3) 3) The price is $ 23.45 . Is that too expensive ? ( I don’t think so . ) import java.io.*; class StreamTokenizerDemo { public static void main(String args[]) { try { FileReader fr = new FileReader(args[0]); BufferedReader br = new BufferedReader(fr); StreamTokenizer st = new StreamTokenizer(br); st.ordinaryChar('.'); st.wordChars('\'', '\''); while(st.nextToken() != StreamTokenizer.TT_EOF) { switch(st.ttype) { case StreamTokenizer.TT_WORD: System.out.println(st.lineno() + ") " + st.sval); break; case StreamTokenizer.TT_NUMBER: System.out.println(st.lineno() + ") " + st.nval); break; default: System.out.println(st.lineno() + ") " + (char)st.ttype); } } fr.close(); } catch (Exception e) { System.out.println("Exception: " + e); } } } Another on ….Data Byte Streams DataInput and DataOutput These interfaces define methods that transmit primitive types across a stream. Read / Write methods Read readBoolean readChar readByte readShort readInt readLong readFloat readDouble readUTF Write Type writeBoolean boolean writeChar char writeByte byte writeShort short writeInt int writeLong long writeFloat float writeDouble double writeUTF String(in UTF format) public static void writeData(double[] data, String file) throws IOException { OutputStream fout = new FileOutputStream(file); DataOutputStream out = new DataOutputStream(fout); out.writeInt(data.length) for(double d : data) out.writeDouble(d); out.close(); } public static double[] readData(String file) throws IOException { InputStream fin = new FileInputStream(file); DataInputStream in = new DataInputStream(fin); double[] data = new double[in.readInt()]; for (int i = 0; i < data.length; i++) data[i] = in.readDouble(); in.close(); return data; } Reading and Writing Objects? What if we could save and store and object and read it (bring it back to life)….wow! Object Serialization What is Object Serialization? • Serialization: process of converting an object’s representation into a stream of bytes • Deserialization: reconstituting an object from a byte stream • Process of reading and writing objects • Writing an object is to represent its state in a serialized form sufficient to reconstruct the object as it is read. • serialization is the process of converting a object state into a format that can be stored (for example, in a file or memory buffer, or transmitted across a network connection link) and "resurrected" later in the same or another computer environment. Serializing Objects How to Write to an ObjectOutputStream • Writing objects to a stream is a straight-forward process. Example of constructing a Date object and then serializing that object: FileOutputStream out = new FileOutputStream("theTime"); ObjectOutputStream s = new ObjectOutputStream(out); s.writeObject("Today"); s.writeObject(new Date()); s.flush(); How to Read from an ObjectOutputStream • Example that reads in the String and the Date object that was written to the file named theTime in the read example: FileInputStream in = new FileInputStream("theTime"); ObjectInputStream s = new ObjectInputStream(in); String today = (String)s.readObject(); Date date = (Date)s.readObject(); Serializing Objects Providing Object Serialization for Your Classes • • • • Implementing the Serializable Interface Customizing Serialization Implementing the Externalizable Interface Protecting Sensitive Information Files ---and Channels+ Accessing Files Channels • Channels were introduced in the 1.4 release of Java to provide a faster capability for a faster capability for input and output operations with files, network sockets, and piped I/O operations between programs than the methods provided by the stream classes. • The channel mechanism can take advantage of buffering and other capabilities of the underlying operating system and therefore is considerably more efficient than using the operations provided directly within the file stream classes. A summary of the essential role of each of them in file operations • A File object encapsulates a path to a file or a directory, and such an object encapsulating a file path can be used to construct a file stream object. • A FileInputStream object encapsulates a file that can be read by a channel. A FileoutputStream object encapsulates a file that can be written by a channel. • A buffer just holds data in memory. The loaded data to be written to a file will be saved at buffer using the buffer’s put() method, and retrieved using buffer’s get() methods. • A FileChannel object can be obtained from a file stream object or a RandomAccessFile object. Accessing Files The hierarchy of the channel interfaces Accessing Files The Capacities of Different Buffers Channel Example (ReadPrimes) import import import import import import java.io.File; java.io.FileInputStream; java.io.IOException; java.io.FileNotFoundException; java.nio.ByteBuffer; java.nio.channels.FileChannel; try { while(inChannel.read(buf) != -1) { ((ByteBuffer)(buf.flip())).asLongBuffer().g et(primes); // List the primes read on the same line System.out.println(); for(long prime : primes) System.out.printf("%10d", prime); public class ReadPrimes { public static void main(String[] args) { File aFile = new File("primes.bin"); From the FileInputStream inFile = null; channel, read buf.clear(); // Clear the try { data and save buffer for the next read inFile = new FileInputStream(aFile);to the buffer } System.out.println("\nEOF reached."); } catch(FileNotFoundException e) { inFile.close(); // Close the file e.printStackTrace(System.err); and the channel System.exit(1); Channel Setup } } catch(IOException e) { e.printStackTrace(System.err); FileChannel inChannel = System.exit(1); inFile.getChannel(); } final int PRIMECOUNT = 6; System.exit(0); ByteBuffer buf = } ByteBuffer.allocate(8*PRIMECOUNT); } You also need to read the long[] primes = new long[PRIMECOUNT]; “PrimesToFile.java” which prints prime numbers to the file. Buffer Setup