Streams

Streams need to perform 4 important operations:

  • open()
  • read()
  • write()
  • close()

Stream operation on files are expensive operation, so not to use for single characters.

Package java.io contains all important classes for reading and writing of character and byte streams.

For Bytes: - Abstract classes are InputStream and OutputStream - Concrete classes are File/ByteArray/Piped Stream

For CharacterStreams - Abstract classes are Reader and Writer - Concrete classes are FileReader/FileWriter

Character input stream

public ArrayList<MyClass> readMyClassObjects() {
  
  BufferedReader br = null;
  
  List<MyClass> myClassList = new ArrayList<MyClass>();
  
  try{
    br = new BufferedReader (new FileReader(file));  
    String title = br.readLine();
    while (title != null){
      String author = br.readLine();
      myClassLijst.add(new MyClass(title, author));
      title = br.readLine();
    }
  
  } catch (FileNotFoundException e){
    
  } catch (IOException e){

  } finally {
  if (br != null){
    try {br.close();
    } catch (IOException e){}
  }
}
    return null;
    
    }

Byte Input stream

 public ArrayList<Book> readMyClassObjects(){
    
    BufferedReader br = null;
    ObjectInputStream ois = null;
    
    try{
      ois = new ObjectInputStream(new FileInputStream(file));
      books = (ArrayList<Book>) ois.readObject();
    } catch (FileNotFoundException e){      
    } catch (IOException e){
    } finally {    
      try {
        ois.close();
      }
      catch (IOException e) {
        e.printStackTrace();
      }
  }
      return null;
}
    

Character output stream

public void writeMyClass(ArrayList<MyClass> myClassList){
  PrintWriter pw = null;
  
    try {
      pw = new PrintWriter(new BufferedWriter(new FileWriter (file, false)));
    
    for(Book book : booklist){
      pw.println(book.getTitle());
      pw.println(book.getTitle());
    }
    
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      if (pw != null){
        pw.close();
      }
    }
  }

Byte Output stream

public void writeMyClass(ArrayList<MyClass> myClassList) {
  ObjectOutputStream writer = null;
  try {
    writer = new ObjectOutputStream(new FileOutputStream(file)); 
    writer.writeObject(booklist);
  }
  catch (IOException e) {
    System.out.println(e.getMessage());
  }
  finally {
    if (writer != null) {
      try {writer.close();}
      catch (IOException ioe) {}
    }
  }
}

It is possible to combine streams (e.g. new BufferedReader(new FileReader()))

Kind of input is variable. Can be file, URL etc…


URL url = new URL('www.google.com');
BufferedReader br = new BufferedReader(new InputStream(url.openStream()));

Different types of Writers FileWriter BufferedWriter PrintWriter can write without throwing exceptions. Need to check for errors by checkErrors () method.

PrintWriter w = null;
try {  
    w = new PrintWriter(    BufferedWriter(FileWriter("foo.txt")));
  } catch (FileNotFoundException e) {}
  if (w != null) {  
    w.println("bar");  
    w.print("baz");  
    w.flush();  
    w.close();
  }

System.out is also stream to which you can write

Serialization and De-serialization

Serialization: Export of objects as byte streams exclusive: - static attributes - classes not implementing the seriazable interface - transient attributes

E.g. Object -> ObjectOutputStream -> FileOutputStream

public class Rekening implements Serializable { ... }
Rekening r = new Rekening();
ObjectOutputStream s =   new ObjectOutputStream(new FileOutputStream("foo.ser"));
s.writeObject(r);

De-serialization: Import objects from byte representations. Powerful mechanism to use. E.g. to send you gui throw internet somewhere else

E.g. FileInputStream -> ObjectInputStream -> -> Object

ObjectInputStream s =   new ObjectInputStream(new FileInputStream("foo.ser"));Object o = s.readObject(); // ClassNotFoundException? 
Rekening r = (Rekening) o; // ClassCastException?

You can mark fields as transient if you want to prevent serialization for this field.

But, serializable opens your attributes (also private)!!! Serialized data can be manipulated outside you application and, as you read the data and use it to build new objects, lead to class invariants

Parser

When a stream is opened it is necessary to extract important data from the input. Therefore the data needs to be parsed.

// Ordinary string to int
Integer.parseInt(line.substring(iBegin,iEnd));
// process tab separated values
String[] s = line.split("\t");

// read in JSON files
JSONParser parser = new JSONParser();
// a. a String line formatted in JSON
JSONObject j = (JSONObject)parser.parse(line);
// b. a whole JSON file
JSONArray ar = (JSONArray)parser.parse(new FileReader(filename));

// An Image
BufferedImage img = ImageIO.read(new File(filename));

Pipe streams



@Test
  public void testPipeOutput() throws IOException {
//    Within java program InputStream is output from external application and OutputStrean input for external application

    // output generating process
    Process generateOutput = new ProcessBuilder("ls").start();

    // input requiring process
    Process processInput = new ProcessBuilder("cat", "-n").start();

//    Writer for stdin of external program
    PrintStream ps = new PrintStream(processInput.getOutputStream());
    PrintStream ps = new PrintStream(new PipedOutputStream());

//    Reader for stdout of external program
    BufferedReader generatedOutputReader = new BufferedReader(new InputStreamReader(generateOutput.getInputStream()));
    String line;
    while((line = generatedOutputReader.readLine()) != null) {
      //write to stdin external program
      ps.println(line);
//      write to display
      System.out.println(line);
      ps.flush();
    }

//    important close statements, particular outputStreamWriter, otherwise loop continues forever
    generatedOutputReader.close();
    ps.close();


//    Just to check what arrived at input requiring process
    BufferedReader processInputInputStreamReader = new BufferedReader(new InputStreamReader(processInput.getInputStream()));
    String input;

    while ((input = processInputInputStreamReader.readLine()) != null) {
      System.out.println(input);
    }
    processInputInputStreamReader.close();
  }

PipedOutputStream upstreamOutputStream = new PipedOutputStream();
PipedInputStream pipedInputStream = new PipedInputStream();
        try {
            upstreamOutputStream.connect(pipedInputStream);
        } catch (IOException e) {
            throw new Exception("Cannot connect upstream output to input");
        }
CommandLine cmd1 = new CommandLine(cmd);     
DefaultExecutor executor;
DefaultExecuteResultHandler resultHandler;   

executor = new DefaultExecutor();
resultHandler = new DefaultExecuteResultHandler();

executor.setStreamHandler(streamHandler);

CommandLineExecutor executor1 = new CommandLineExecutor(cmd, upstreamOutputStream, toolErrorOutputStream, toolInputStream);

OutputStream toolStandardOutputStream = CommandLineExecutor.createLogOutputStream(Level.INFO);
CommandLine pipeCmd = new CommandLine(cmd);        
CommandLineExecutor executor2= new CommandLineExecutor(cmd, toolStandardOutputStream, toolErrorOutputStream, pipedInputStream);

executor2.start()

Pipe streams (multithread)


@Test
  public void pipeOutputTest() throws IOException {
    final PipedOutputStream output = new PipedOutputStream();
    final PipedInputStream input = new PipedInputStream(output);

    final PipedWriter pw = new PipedWriter();
    final PipedReader pr = new PipedReader(pw);

    Thread thread1 = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          output.write("Hello world, pipe!\n".getBytes());
          pw.write("Hello world writer\n");
        } catch (IOException e) {
        }
      }
    });


    Thread thread2 = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          int data = input.read();
          while (data != -1) {
            System.out.print((char) data);
            data = input.read();
          }
        } catch (IOException e) {
        }
        try {
          int data = pr.read();
          while (data != -1) {
            System.out.print((char) data);
            data = pr.read();
          }
        } catch (IOException e) {
        }

      }
    });

    thread1.start();
    thread2.start();
  }