Introducere

Fluxurile de intrare \ ieşire reprezintă mecanismele prin intermediul cărora programele java pot citi \ scrie date de la şi către diverse destinaţii (fişiere, alte programe, memorie, resurse de reţea, dispozitive etc.).

Un flux este un canal de comunicaţie unidirecţional prin intermediul căruia datele pot fi citite sau scrise.

Prin intermediul fluxurilor de intrare datele sunt citite. Prin intermediul fluxurilor de ieşire datele sunt transmise către o destinaţie.

Figura 1. Fluxurile de intrare şi ieşire.

În java există două tipuri de fluxuri: fluxuri orientate pe byte şi fluxuri orientate pa caracter.

Fluxurile orientate pe byte sunt folosite in general pentru scrierea şi citirea de date binare (imagini, sunete, obiecte, etc), array-uri de date.

Figura 2. Fluxurile din citire \ scriere orientate pe byte.

Fluxurile de citire orientate pe byte au la bază clasa InputStream iar fluxurile de scriere au la baza clasa OutputStream.

Fluxurile orientate pe caracter au fost introduse in versiunea 1.1. a java şi sunt destinate pentru manipularea şirurilor de caractere (scrierea şi citirea se face pe 16 biţi).

Figura 3. Fluxurile de citire \ scriere orientate pe caracter.

Fluxurile de citire orientate pe caracter au la bază clasa Reader iar fluxurile de scriere au la baza clasa Writer.

Pentru majoritatea programelor scrierea si citirea datelor se va face prin intermediul fluxurilor de caractere deoarece acestea permit manipularea caracterelor Unicode (16-biti), in timp ce fluxurile de octeţi permit doar lucrul pe 8 biţi.

Utilizare fluxurilor de intrare / ieşire

Aplicaţia următore exemplifică modul în care fluxurile de intrare ieşire pot fi folosite pentru scrierea şi citirea de date din cadrul aplicaţiilor java.

import java.io.*;
public class IOStreamDemo {
 
      public static void main(String[] args)
        throws IOException {
          // 1. Reading input by lines:
          BufferedReader in = new BufferedReader(
            new FileReader(".project"));
          String s, s2 = new String();
          while((s = in.readLine())!= null)
            s2 += s + "\n";
          in.close();
 
          // 1b. Reading standard input:
          BufferedReader stdin = new BufferedReader(
            new InputStreamReader(System.in));
          System.out.print("Enter a line:");
          System.out.println(stdin.readLine());
 
          // 2. Input from memory
          StringReader in2 = new StringReader(s2);
          int c;
          while((c = in2.read()) != -1)
            System.out.print((char)c);
 
          // 3. Formatted memory input
          try {
            DataInputStream in3 = new DataInputStream(
              new ByteArrayInputStream(s2.getBytes()));
            while(true)
              System.out.print((char)in3.readByte());
          } catch(EOFException e) {
            System.err.println("End of stream");
          }
 
          // 4. File output
          try {
            BufferedReader in4 = new BufferedReader(
              new StringReader(s2));
            PrintWriter out1 = new PrintWriter(
              new BufferedWriter(new FileWriter("IODemo.out")));
            int lineCount = 1;
            while((s = in4.readLine()) != null )
              out1.println(lineCount++ + ": " + s);
            out1.close();
          } catch(EOFException e) {
            System.err.println("End of stream");
          }
 
          // 5. Storing & recovering data
          try {
            DataOutputStream out2 = new DataOutputStream(
              new BufferedOutputStream(
                new FileOutputStream("Data.txt")));
            out2.writeDouble(3.14159);
            out2.writeUTF("That was pi");
            out2.writeDouble(1.41413);
            out2.writeUTF("Square root of 2");
            out2.close();
            DataInputStream in5 = new DataInputStream(
              new BufferedInputStream(
                new FileInputStream("Data.txt")));
            // Must use DataInputStream for data:
            System.out.println(in5.readDouble());
            // Only readUTF() will recover the
            // Java-UTF String properly:
            System.out.println(in5.readUTF());
            // Read the following double and String:
            System.out.println(in5.readDouble());
            System.out.println(in5.readUTF());
          } catch(EOFException e) {
            throw new RuntimeException(e);
          }
 
          // 6. Reading/writing random access files
          RandomAccessFile rf =
            new RandomAccessFile("rtest.dat", "rw");
          for(int i = 0; i < 10; i++)
            rf.writeDouble(i*1.414);
          rf.close();
          rf = new RandomAccessFile("rtest.dat", "rw");
          rf.seek(5*8);
          rf.writeDouble(47.0001);
          rf.close();
          rf = new RandomAccessFile("rtest.dat", "r");
          for(int i = 0; i < 10; i++)
            System.out.println("Value " + i + ": " +
              rf.readDouble());
          rf.close();
 
        }
      } //.

Fluxuri standard de intrare / ieşire

În cadrul clasei System sunt definite fluxurile standard de intrare / ieşire System.in (in este un atribut static de tip InputStream definit în cadrul clasei System) şi System.out (out este un atribut static de tip OutputStream definit în cadrul clasei System) care sunt conectate în mod implicit la ecran respectiv tastatură. Exemplu următor prezintă modul în care poate fi folosit fluxul de intrare standard pentru citirea datelor. Pe lângă aceste două fluxuri în cadrul clasei System este definit şi fluxul err (atribut static de tip OutputStream definit în cadrul clasei System) care poate fi folosit pentru raportarea mesajelor de eroare.

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;
 
public class StandardIOExemplu {
 
      static String sortChars(String s){
            char[] a = s.toCharArray();
            Arrays.sort(a);
            return new String(a);
      }
 
      public static void main(String[] args) {
 
            try{
           BufferedReader fluxIn = new BufferedReader(new InputStreamReader(System.in));
           String linie = "";
                 do{
                   System.out.print(">");
                   linie = fluxIn.readLine();
                   System.out.println("result:"+sortChars(linie));
                 }while(linie.indexOf("end")==-1);    
            }catch(Exception e){
                  e.printStackTrace();
                  System.err.println("Eroare :"+e.getMessage());
 
            }
      }
}

Fluxurile standard pot fi redirectate folosind metodele setOut(), setIn() şi setErr() din cadrul clasei System.

import java.io.*;
class Redirectare {
      public static void main(String[] args) {
            try {
                  BufferedInputStream in = new BufferedInputStream(
                        new FileInputStream(".project"));
                  PrintStream out = new PrintStream(new BufferedOutputStream(
                        new FileOutputStream("test.out")));
                  System.setIn(in);
                  System.setOut(out);
                  System.setErr(out);
 
                  BufferedReader br = new BufferedReader(
                              new InputStreamReader(System.in));
                  String s;
                  while((s = br.readLine()) != null)
                        System.out.println(s);
                  out.close();
            } catch(IOException e) {
                  e.printStackTrace();
            }
      }
}

Fluxuri de tip pipe

Fluxurile de tip pipe sunt folosite pentru a trimite date intre două componente ale aceluiaşi program. Utilitatea acestor tipuri de fluxuri va deveni evidentă în momentul în care se va discuta despre fire de execuţie şi aplicaţii multifir. Limbajul java permite construirea de pipe-uri orientate pe byte folosind clasele PipedInputStream / PipedOutputStream şi fluxuri orientate pe caracter folosind clasele PipedReader / PipedWriter.

import java.io.*;
 
public class Piped2Example {
public static void main(String[] args) {
      try{ 
            PipedReader in = new PipedReader();
            PipedWriter out = new PipedWriter();
            in.connect(out);
 
            //scrie date in pipe
                  out.write("mesaj scris in pipe");
 
            //citeste din pipe
            while(in.ready()){
                  int x = in.read();
                  System.out.println("Read from pipe:"+(char)x);
            }
 
      }catch(Exception e){
            e.printStackTrace();
      }
}
}//.

Compresia datelor folosind fluxuri

În cadrul pachetului java.util.zip sunt definite fluxuri de intrare ieşire ce permit comprimarea şi decomprimarea datelor. Programul următor exemplifică modul în care poate fi comprimat / decomprimat un fişier.

import java.io.*;
import java.util.zip.*;
 
public class ZipUtil {
 
      void compressFile(String source, String dest){
          try {
              // Create the GZIP output stream
              String outFilename = dest;
              GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(outFilename));
 
              // Open the input file
              String inFilename = source;
              FileInputStream in = new FileInputStream(inFilename);
 
              // Transfer bytes from the input file to the GZIP output stream
              byte[] buf = new byte[1024];
              int len;
              while ((len = in.read(buf)) > 0) {
                  out.write(buf, 0, len);
              }
              in.close();
 
              // Complete the GZIP file
              out.finish();
              out.close();
          } catch (IOException e) {
            System.out.println("Error compressing file:"+e.getMessage());
          }
      }
 
      void decompressFile(String source, String dest){
             try {
                    // Open the compressed file
                    String inFilename = source;
                    GZIPInputStream in = new GZIPInputStream(new FileInputStream(inFilename));    
                    // Open the output file
                    String outFilename = dest;
                    OutputStream out = new FileOutputStream(outFilename);
 
                    // Transfer bytes from the compressed file to the output file
                    byte[] buf = new byte[1024];
                    int len;
                    while ((len = in.read(buf)) > 0) {
                        out.write(buf, 0, len);
                    }      
                    // Close the file and stream
                    in.close();
                    out.close();
                } catch (IOException e) {
                  System.out.println("Error decompressing file:"+e.getMessage());
                }
      }
 
      void generateFile(String name, long size){
 
            try {
                  FileOutputStream s = new FileOutputStream(new File(name));
                  for(int i=0;i<size;i++){
                        int c = (int)(40+Math.random()*50);
                        s.write(c);
                  }
            } catch (FileNotFoundException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
            } catch (IOException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
            }    
      }
 
      public static void main(String[] args) {
            ZipUtil zu = new ZipUtil();
 
            zu.generateFile("test.txt", 1024);
            zu.compressFile("test.txt", "test.gzip");
            zu.decompressFile("test.gzip","decompressed.txt");   
      }    
 
}