Un I/O Stream o fluxe d'entrada/sortida representa un origen de dades i una destinació de dades qualsevol. Un Stream pot representar diferents tipus d'origens i/o destinacions:
Fitxers o disk files Dispositius de hardware devices i/o perifèrics Altres programes Memory arrays network sockets ...
Els streams de java suporten diferents tipus de dades des de bytes, a tipus de daes primitius (enters, booleans, etc), caracters 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:
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ó.
Recursos:
Són les classes abstractes en la que es basen tots els tipus d'Streams en Java.
Els Byte Streams o fluxos de bytes són el tipus d'streams o fluxes més basics. Cal tenir en compte que el byte (més que el bit) és la unitat típica mínima d'opetacions 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 clases d'aquest tipus són filles de les clases InputStream i OutputStream.
Hi ha múliples 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.
Els fitxers es poden llegir i escriure utilitzant les clases 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:
TODO: http://docs.oracle.com/javase/tutorial/essential/io/bytestreams.html
http://docs.oracle.com/javase/tutorial/essential/io/bytestreams.html
NOTA: El fitxer ha d'estar a la mateixa carpeta on s'executa el programa i s'ha de dir exactament igual. podeu indicar un path complet, però OCO! la forma en que s'especifiquen paths depèn del sistema operatiu i pot fer que la vostra aplicació deixi de ser multiplataforma
Observeu el tros de codi:
IMPORTANT: Sempre cal tancar els streams per alliberar recursos. Fixeu-vos l'ús del bloc finally per assegurar-se que el stream es tanqui inclús en cas d'errors. Aquesta tècnica permet eviar els resource leaks o especificament els memory leaks
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 interesant treballar amb streams de caràcters.
NOTA: Que no sigui la forma més eficient no vol dir que no valgui la penda entendre com funciona, ja que tota la resta d'Streams es basen en Streams de bytes
Vegeu Android i fitxers de l'article Android Storage.
Reader i Writer, les classes pare de qualsevol stream basat en caràcters.
Java utilitza Unicode per emmagatzemar caràcters. Els streams de caràcters automàticament tradueixen el fotmat intern d'un strema al format local (depenent del joc de caràcters local). Els Western locales (prvis a unicode) acosutem a ser variants de ASCII de 8 bits
La majoria d'aplicacions no són més complexes si utilitzen Caràcters en comtpes de bytes, però això depèn del nivell d'importància de la Internacionalització i Localització de l'aplicació.
NOTA: Si la internacionalització no és una prioritat, simplement es poden utilitzar els streams de caràcters sense parar massar atenció en els tipus de caràcters
Les classes bàsiques són FileReader i FileWriter, filles de Reader i Writer, les classes pare de qualsevol stream basat en caràcters.
IMPORTANT: Tots els streams de caràcters són fills de les classes Reader i Writer. Igual que amb els byte streams hi ha unes classes especialitzades en fitxers: FileReader i FileWriter
java.io.FileReader java.io.FileWriter
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.
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(); } } } }
L'exemple CopyCharacters és 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
TODO:
There are two general-purpose byte-to-character "bridge" streams: InputStreamReader and OutputStreamWriter. Use them to create character streams when there are no prepackaged character stream classes that meet your needs. The sockets lesson in the networking trail shows how to create character streams from the byte streams provided by socket classes.
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.
IMPORTANT: Compte que el terminador de línia no és igua len totes les plataformes: ("\r\n"),("\r"), ("\n"). Java suporta tots els tipus
Vegem ara un exemple de copia per línies utilitzant:
BufferedReader i PrintWriter
import java.io.FileReader; import java.io.FileWriter; import java.io.BufferedReader; import java.io.PrintWriter; import java.io.IOException; 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.
Recursos:
TODO Clase Scanner
Vegeu també Serialització.
Exemples amb Android:
Android_sockets#Com_utilitzar_un_objecte_per_controlar_les_acciones_que_es_duen_a_terme