IMPORTANT: Per accedir als fitxer de subversion: http://acacha.org/svn (sense password). Poc a poc s'aniran migrant els enllaços. Encara però funciona el subversion de la farga però no se sap fins quan... (usuari: prova i la paraula de pas 123456)

I/0 Streams

Un I/O Stream o flux d'entrada/sortida representa un origen de dades i una destinació de dades qualsevol. Un Stream pot representar diferents tipus d'orígens i/o destinacions:

Els streams de java suporten diferents tipus de dades des de bytes, a tipus de dades primitius (enters, booleans, etc), caràcters localitzats, objectes...

Els streams simplement mouen les dades, la manipulació de les mateixes la fan tercers, no els propis streams.

No importa com funcionin els streams internament, tots representen el mateix model:

Andrescorazon java input stream.png
Andrescorazon java output stream.png

Un stream és una seqüència ordenada de dades. Els programes utilitzen streams d'entrada per llegir dades d'una font o streams de sortida per enviar dades a una destinació.

InputStream i OutputStream

Són les classes abstractes en la que es basen tots els tipus d'Streams en Java.

Byte Streams

Els Byte Streams o fluxos de bytes són el tipus d'streams o fluxos més bàsics. Cal tenir en compte que el byte (més que el bit) és la unitat típica mínima d'operacions d'entrada/sortida (I/O).

Els programes Java utilitzen byte streams per realitzar operacions d'entrada sortida en unitats de 8 bits = 1 byte. Totes les classes d'aquest tipus són filles de les classes InputStream i OutputStream.

Hi ha múltiples tipus de classes byte stream, algunes s'expliquen als següents apartats. Cal tenir en compte que totes funcionaran de forma similar, l'únic que canviarà serà la creació del Stream.

FileInputStream i FileOutputStream

Els fitxers es poden llegir i escriure utilitzant les classes FileInputStream i FileOutputStream.

Vegem un exemple:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyBytes {
    public static void main(String[] args) throws IOException {

        FileInputStream in = null;
        FileOutputStream out = null;

        try {
            in = new FileInputStream("in.txt");
            out = new FileOutputStream("out.txt");
            int c;

            while ((c = in.read()) != -1) {
                out.write(c);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
}

Aquest exemple el que fa és agafar un fitxer d'entrada (in.txt) i copia tot el seu contingut a out.txt.

El més important és el tros de codi:

while ((c = in.read()) != -1) {
               out.write(c);
           }

On anem llegint byte a byte el fitxer original, segons es pot veure a la gràfica següent:

Andrescorazon byte stream.png

Cal tenir en compte que els Byte Streams no són la forma més eficient de treballar amb dades I/O, ja que estem treballant a un nivell molt baix de sistema, és a dir, de la forma més primitiva possible. Per exemple per a un fitxer podria ser més interessant treballar amb streams de caràcters.

Character Streams. Reader i Writer

Reader i Writer, les classes pare de qualsevol stream basat en caràcters.

FileReader i FileWriter

Java utilitza Unicode per emmagatzemar caràcters. Els streams de caràcters automàticament tradueixen el format intern d'un stream al format local (depenent del joc de caràcters local). Els Western locales (previs a Unicode) acostumen a ser variants de ASCII de 8 bits.

La majoria d'aplicacions no són més complexes si utilitzen caràcters en comptes de bytes, però això depèn del nivell d'importància de la Internacionalització i Localització de l'aplicació.

Les classes bàsiques són FileReader i FileWriter, filles de Reader i Writer, les classes pare de qualsevol stream basat en caràcters.

Els streams de caràcters són sovint "wrappers" d'streams de bytes. El stream de caràcters utilitza un stream de bytes per a realitzar operacions físiques de I/O, mentres que els streams de caràcters controlen les traduccions entre caràcters y bytes.

Vegem un exemple:

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyCharacters {
    public static void main(String[] args) throws IOException {

        FileReader inputStream = null;
        FileWriter outputStream = null;

        try {
            inputStream = new FileReader("xanadu.txt");
            outputStream = new FileWriter("characteroutput.txt");

            int c;
            while ((c = inputStream.read()) != -1) {
                outputStream.write(c);
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }
}

CopyCharacters es molt similar a CopyBytes. L'única diferencia és en els objectes:

FileInputStream -> FileReader
FileOutputStream -> FileWriter

Cal tenir en compte que tots treballen amb ints, però de diferent mida!

CopyCharacters -> 16 bits
CopyBytes -> 8 bits
Line-Oriented I/O

El procesament de caràcters sovint es fa en unitats de dades més grans que simples caràcters. un cas típic és operar a nivell de línies. La definició de línia és:

Un string de caràcters amb un terminador de línia al final.

Vegem ara un exemple de copia per línies utilitzant:

BufferedReader i PrintWriter
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class CopyLines {

	public static void main(String[] args) throws IOException {
		
		BufferedReader inputStream = null;
		PrintWriter outputStream = null;

		try {
			inputStream = new BufferedReader(new FileReader("xanadu.txt"));
			outputStream = new PrintWriter(new FileWriter("characteroutput.txt"));

			String l;
			while ((l = inputStream.readLine()) != null) {
				outputStream.println(l);
			}
		} finally {
			if (inputStream != null) {
				inputStream.close();
			}
			if (outputStream != null) {
				outputStream.close();
			}
		}
	}

}

L'ús del mètode readLine retorna una línia de text. Per a mostrar les línies per sortida utlitzen println que s'encarrega d'afegir el terminador de línia al final.

Vegeu també

Enllaços externs