Date post: | 31-Dec-2015 |
Category: |
Documents |
Upload: | spencer-porter |
View: | 217 times |
Download: | 4 times |
Lecture 7 - streams
AdvancedJava
Programming
1
dr hab. Szymon Grabowskidr inż. Wojciech [email protected]://wbieniec.kis.p.lodz.pl
What is a streamProgramming of I/O operationsin Java is to use streams that are class in the package java.io
Table: The ancestors of the class hierarchy stream - abstract classes
Input Output
Byte Streams InputStream OutputStream
Character sterams
Reader Writer
The data stream is a logical concept.
Means a structure similar to a queue to which the data can be added and from which data can be downloaded.
Basic operations on the stream: read and write data.
3
Basic classes for reading and writing sequences of bytes are FileInputStream and FileOutputStream.
FileInputStream inp = new FileInputStream("1.dat");FileOutputStream outp = new FileOutputStream("2.dat");
Read a byte (0..255), write a byte: int read(); write(int);
Read value –1 signals the end of file.
The (main) hierarchy of input / output classes starts withabstract classes InputStream and OutputStream.
Intro to I/O
When we create a file object (eg. of any of the two just mentioned classes), the file is open.
44
Don’t forgetexceptionhandling!
Byte-by-byte copy example
5
We already know that read() is abstract.The methods
read(b) == read(b, 0, b.length)
If b.length == 0 (or param len == 0 in the latter method), then the methods return 0.Nothing to read (EOF)? The methods return –1.
read(...) methods from InputStream
int read(byte[ ] b),int read(byte[ ] b, int off, int len)
are non-abstract, but they internally invoke read().
Moral: any subclass of InputStreammust implement read().
Binding the stream with the source or receiver
Table: Subject classes (associated with a particular source / receiver)
Source/receiverCharacter streams Byte streams
Memory CharArrayReaderCharArrayWriter
ByteArrayInputStreamByteArrayOutputStream
StringReaderStringWriter
(not used because of improper byte-to-character conversion)
Pipeline (allows exchange data between two threads)
PipedReader PipedWriter
PipedInputStreamPipedOutputStream
File FileReader FileWriter
FileInputStreamFileOutputStream
7
FileInputStream and FileOutputStream can read / write only bytes.
Fortunately, there are classes DataInputStream, DataOutputStream, but...their constructors obtain an abstract stream(InputStream, OutputStream, respectively).
How to work with files?
The solution is typical for Java I/O: combining filters.
FileInputStream fin = new FileInputStream("numbers.dat");DataInputStream din = new DataInputStream(fin);
double x = din.readDouble();
Combining stream functionalities
Would be useful to have classes for reading / writing int, longs, doubles...
8
DataInputStream din = new DataInputStream(new BufferedInputStream(new FileInputStream("numbers.dat")));
The Decorator pattern lets us add functionality to an object at runtime.
Actually this is the Decorator design pattern
The idea. Object x from class X contains object y from Y. Object x will be called a decorator.
x forwards method calls to y.x conforms to the interface of y, which allowsthe decorator to be used as if x were an instance of Y.(But typically x has its own capabilities, not existing in y.)
9
FileOutputStream(String name)FileOutputStream(String name, boolean append)FileOutputStream(File file)FileOutputStream(File file, boolean append)
append == true data are added at the end of the file(otherwise an existing file is deleted and start from scratch)
FileOutputStream constructors
Transforming classesIn I/O operations data transformation can be performed.
Type of processingCharacter streams Byte streams
Bufferinf BufferedReaderBufferedWriter
BufferedInputStreamBufferedOutputStream
Filtering – these classes define the methods for final filtersFinal filters are: DataInputStream & DataOutputStream, BufferedInputStream BufferedOutputStream. LineNumberInputStream, PushbackInputStream, PrintStream. You can create custom filters
FilterReaderFilterWriter
FilterInputStreamFilterOutputStream
Java has many classes specialized in automatic processing specific types of streams.
These classes implement certain types of process streams, regardless of the source / receiver
Transforming classesType of processing
Character streams Byte streams
Byte-to-character conversion
InputStreamReaderOutputStreamWriter
Concatenate SequenceInputStream
Object serialization ObjectInputStream ObjectOutputStream
Data conversion DataInputStream DataOutputStream
Line counting LineNumberReader LineNumberInputStream
Previewing PushbackReader PushbackInputStream
Printing PrintWriter PrintStream
To apply processing classes you must:Create an object associated with a physical source.receiverCreate an object that is overlayed on the physical stream
12
Use FileReader, FileWriter classes.
FileReader: converts from the default codepage to Unicode. FileWriter: the other way around...
import java.io.*;public class ReadByReader { public static void main(String[] args) { StringBuffer cont = new StringBuffer(); try { FileReader inp = new FileReader(args[0]); int c; while ((c=inp.read()) != -1) cont.append((char)c); inp.close(); } catch(Exception e) { System.exit(1); } String s = cont.toString(); System.out.println(s); }}
Text I/O
13
If the characters in the file to read adhere to non-standard encoding, don’t use FileReader.
FileInputStream fis = new FileInputStream("test.txt");InputStreamReader isr = new InputStreamReader(fis, "UTF8");
Non-standard character encoding
Use its parent class, InputStreamReader, instead.OutputStreamWriter for writing, of course.
14
On slide 8, the method read(), from InputStreamReader (not FileReader), was used.
Reading a text (character) file
It reads a single char (a variant reading a number of chars into an array also exists).
For a greater flexibility, use Scanner.
15
For writing to a text file, use PrintWriter
BufferingBuffering reduces the number of physical references to external devices.
For example, reading large text files it should be avoided by reading the FileReader class.
Using BufferedReader class will improve the effectiveness of the program. But BufferedReader class is a processing claass, therefore can not directly
take the physical data source. This source is served to the FileReader object which is wrapped into a BufferedReader
FileReader fr = new FileReader("plik.txt");BufferedReader br = new BufferedReader(fr);String line;while ((line - br. readLine()) != null){// processinf a line}
Buffering find a word in a file
class Search{ public boolean hasAnyWord(String fname, Hashtable wordtab) { boolean result = false; try{ String line; FileReader fr = new FileReader(fname); BufferedReader br = new BufferedReader(fr);
br.close(); } catch (IOException e){ System.err.println(e); } return result; }}
search: while ((line = br.readLine()) != null ){ StringTokenizer st = new StringTokenizer(line, " ,.:;()\t\r\n"); while (st.hasMoreTokens()){ String word = st.nextToken(); if (wordtab.get(word) != null){ result = true; break search; } } }
Buffering find a word in a file
public class Szukaj{ public static void main(String[] args){/* argumenty: nazwa_pliku slowo1 slowo2 ... */ if (args.length < 2) System.exit(1);
Search srch = new Search(); boolean result = srch.hasAnyWord(args[0], words); String msg = " nie zawiera zadnego ze slow:"; if (result) msg = " zawiera ktores ze slow:"; System.out.println("Plik "+args[0]+msg); Enumeration en = words.keys();// uzyskujemy wszystkie klucze tablicy while (en.hasMoreElements()){ // ... i przebiegamy je po kolei String word = (String) en.nextElement(); System.out.println(word); } }}
Object dummy = new Object(); Hashtable words = new Hashtable(); for (int i = 1; i<args.length; i++) words.put(args[i], dummy);
encodingava uses Unicode characters. These are 16-bit size.
If the constructors of these classes do not specify an encoding, the conversions will be accepted by default.
public class DefaultEncoding{ public static void main(String args[]) { String p = System.getProperty("file.encoding") ; System.out.println(p); }}
Exemplary results: ISO8859_1, ibm-852, Cp852 (Latin 2) , Cpl252 (Windows Western Europe/Latin-1).
Character streams can - invisible to us - convert the source byte character streams, and vice versa. "Under cover" of this process, there are two classes:
InputStreamReader and OutputStreamWriter, which make the appropriate conversions when reading / writing.
HTML conversionimport java.io.*;public class Convert{ public static void main(String[] args) { String infile = args[0],// plik we in_enc = args[1], // strona kodowa wejścia outfile = args[2], // plik wynikowy out_enc = args[3]; // strona kodowa wyjścia
int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close(); } catch (IOException e){ System.err.println(e);} }}
try{ FileInputStream fis = new FileInputStream(infile); InputStreamReader in = new InputStreamReader(fis, in_enc); FileOutputStream fos = new FileOutputStream(outfile); OutputStreamWriter out = new OutputStreamWriter(fos, out_enc);
21
In Java, there exists a powerful mechanism for storing arbitrary objects in files (e.g., on disk).Or, more generally, sending them to a stream.
We save objects and then can recover them.This uses object serialization.
Basically, we can use methods writeObject()and readObject() – for any objects.
myOutFile.writeObject(thisObject);val = (MyClass)myInFile.readObject(); // casting necessary
Object I/O
22
We shall use classes derived from OutputStream and InputStream:
OutputStreamFileOutputStreamObjectOutputStream
InputStreamFileInputStreamObjectInputStream
Import them from java.io.
Object I/O
23
For output:
ObjectOutputStream out;out = new ObjectOutputStream (
new(FileOutputStream("myFile.dat") );// use out.writeObject(...)out.close();
For input (say, we read from the same file):
ObjectInputStream inp;inp = new ObjectOutputStream (
new(FileOutputStream("myFile.dat") );// use inp.readObject()inp.close();
Object I/O
24
writeObject() is powerful. It converts an object of any class into a bit sequence and then
sends it to a stream, in a way that it can be subsequently retrieved
(using readObject()) as an object of the original class.
Not surprisingly, static fields are NOT written to the stream.
Serialized objects may contain e.g. other objects as their fields.
No problem with e.g. arrays either.Even multi-dim arrays (btw, in Java a 2-d array is,
formally speaking, an array of arrays).
Object serialization
25
Our class must simply implement the interfaceSerializable.
public class Tank implements Serializable { ... }
Serializable is empty (=has no methods)!Marker interfaces simply make possible to check
a data type, e.g. with instanceof operator.
That’s what the writeObject(...) method does:checks if
x instanceof Serializable == true.
If so, it sends the object to a stream, otherwise it doesn’t.
(Other marker interfaces: Clonable, RandomAccess...)
How to serialize our own class
26
When we read an object with readObject(),what we get is actually an object of the class Object().
Cast examples:
Student s = (Student)inpFile.readObject();
int[] tab = (int[])inpFile.readObject();
Casting required
27
The signatures are:
public final readObject() throws IOException, ClassNotFoundException;
public final void writeObject(Object obj)throws IOException;
Remember about (checked) exceptions
28
public class GradStudent{ private Supervisor sv; ... }// many grad students may have the same supervisor
No problem! Each GradStudent storesa ‘reference’ to the same Supervisor.
BUT! Those refs are not just mem addresses!Instead, SERIALizable objects get unique
SERIAL numbers.
What if an object is shared by a coupleothers as part of their state?
29
• each encountered object reference gets a unique serial number,
• if an object reference is encounted for the first time, the object data are saved to the output stream,
• else (object ref already saved), it is written that here we have the same object as the one already saved with serial number x.
Reading back: reversed procedure.
Serialization algorithm
30
Yes.
Mark a field with keyword transient and it won’t be serialized.
E.g. (example from Core Java, vol. 2):
public class LabeledPoint implements Serializable{ . . . private String label; private transient Point2D.Double point;}
// because Point2D.Double from java.awt.geom // is not serializable and we want to avoid NonSerializableException
Can we serialize selected fields?
31
Sometimes we’re not happy with the default serialization mechanism.
Cont’d previous slide example:we do want to serialize the data from the Point2D.Double field.
Shall we write the serialization routine from scratch?
First we label the Point2D.Double field as transient (of course).Then we implement
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
private void writeObject(ObjectOutputStream out) throws IOException;
A serializable class is allowed to define those methods.
Serialize on our own
32
private void writeObject(ObjectOutputStream out) throws IOException{ out.defaultWriteObject(); // can be called only from writeObject(...) ! out.writeDouble(point.getX()); out.writeDouble(point.getY());}
private void readObject(ObjectInputStream in) throws IOException{ in.defaultReadObject(); // can be called only from readObject(...) ! double x = in.readDouble(); double y = in.readDouble(); point = new Point2D.Double(x, y);}
Serialize on our own, cont’d
33
writeObject(...) writes several things, incl. class nameand 8-byte class fingerprint.
The fingerprint is to ensure the class definition has not changed (between serialization and deserialization).
What if it has changed?
Indicate that the new class is compatible with the old one.
Run serialver OurClass for the old class to obtain its fingerprint.
Then add as (e.g.):public static final long serialVersionUID =
-1814239825517340645L;to the new version of OurClass.
No problemif only methods
changed.
If new fields added: risky.
If field type changed: even worse.
Versioning
34
The package java.util.zip contains several classes for data compression / decompression.
A few class examples:
Deflater – in-memory compression using zlib library
Inflater – in-memory decompression using zlib library
GzipOutputStream – compresses data using the GZIP format. To use it, construct a GZIPOutputStream that wraps a regular output stream and use write() to write compressed data
GzipInputStream – like above, but for reading data
ZipOutputStream, ZipInputStream – I won’t offend your intelligence
ZipEntry – represents a single element (entry) in a zip file
java.util.zip (compressed I/O)
35
Writing to a stream of GZipOutStream type. Which means it’ll be compressed on-the-fly.
Compression example (using gzip format)
36
Used to read the entries in a zip file. In order to create or to read these entries,
you have to pass a file as argument to the constructor:ZipFile zipfile = new ZipFile(new File("c:\\test.zip"));
This instantiation can throw a ZipException, as well as IOException.
One of the solutions is to surround it in a try/catch:
try { zipfile = new ZipFile(new File("c:\\test.zip"));} catch (ZipException e) { } catch (IOException e) { }
Now, files in a zip can be e.g. listed.
ZipFile class
37
Listing a zip file
38
Representation of a file or directory path name.This class contains several methods for
working with the path name, deleting and renaming files, creating new directories, listing the contents of a directory, etc.
File f1 = new File("/usr/local/bin/dog");File f2 = new File("d:/my_pets/cat1.txt");File f3 = new File("cat.txt");
File g = new File("/windows/system");File h = new File(g, "rabbit.gif");File i = new File("/windows/system", "rabbit.gif");// objects h and i refer to the same file!
File class
39
Selected methods (1/2)
boolean canRead() // Returns true if the file is readableboolean exists() // Returns true if the file existsboolean isDirectory() // Returns true if the file name is a directoryboolean isFile() // Returns true if the file name
// is a "normal" file (depends on OS)long length() // Returns the file lengthboolean setReadOnly() // (since 1.2) Marks the file read-only
// (returns true if succeeded)boolean delete() // Deletes the file specified by this name.boolean mkdir() // Creates this directory.
// All parent directories must already exist.
File class
FileFilter: public interface with only one method:boolean accept(File pathname);
// tests if the specified pathname should be included in a pathname list FileNameFilter: similar interface
but the arg list for accept() different
Beware: JFileChooser (Swing) makes use of javax.swing.filechooser.FileFilter, not java.io.FileFilter! 40
Selected methods (2/2)
String[] list() // Returns an array of Strings with names of the // files from this directory. Returns null if not a dir.
String[] list(FileNameFilter filter)
File[] listFiles()File[] listFiles(FileFilter)File[] listFiles(FileNameFilter) // (all three since 1.2)
File class