Els fluxos de dades estàndard son uns canals de comunicació interconnectats
entre un programa i el seu entorn en moment d'execució. Hi ha tres canals
d'E/S: l'entrada estàndard (standard input o stdin), l'eixida estàndard (standard output o stdout)
i l'eixida d'error (standard error o (stderr).
Aquests fluxos estan connectats a la consola del sistema. Quan un programa s'executa
mitjançant una shell interactiva, aquests canals estan connectats a la terminal,
però poden ser redirigits a altres fitxers o altres processos.
Entrada estàndard (stdin): És un flux de dades d'on el programa pot rebre i llegir
dades d'entrada.
Si no ha segut redirigit, aquest flux rep les dades des del teclat.
En Java, aquest flux de dades està associat a System.in i pot ser llegit
mitjançant la classe Scanner.
Els fluxos de dades treballen per defecte amb el teclat (stdin) o la terminal (stdout i stderr).
No obstant això, aquests fluxos es poder redirigir cap a altres fonts utilitzant diferents operadors.
Redirecció eixida >: Crea un nou fitxer contenint l'eixida estàndard (no la d'error!)
del programa executat. Atenció, si el fitxer existeix, aquest és sobreescrit
(i es perden les dades existents)
Redirecció d'eixida en Bash
jpuigcerver@fp:~/psp$ls
jpuigcerver@fp:~/psp$echo"Aquesta informació s'imprimeix per stdout"Aquesta informació s'imprimeix per stdoutjpuigcerver@fp:~/psp$echo"Aquesta informació s'imprimeix per stdout">stdout.txt
jpuigcerver@fp:~/psp$ls
stdout.txtjpuigcerver@fp:~/psp$catstdout.txt
Aquesta informació s'imprimeix per stdout
Aquest exemple comença amb la comanda ls, que mostra els continguts del directori
actual, on es pot veure que està buit.
Després, s'executa echo, que funciona com un print i mostra per pantalla (stdout)
la informació:
Aquesta informació s'imprimeix per stdout"
Després es torna a executar, redirigint l'eixida al fitxer stdout.txt amb
l'operador de redirecció >.
Finalment, es mostra el contingut del fitxer stdout.txt, amb la informació anterior.
Redirecció afegir eixida >>: Afegeix (append) un fitxer l'eixida estàndard (no la d'error!).
Si el fitxer no existeix es crea. Les noves dades s'afegeixen al final del fitxer
i no s'eliminen les dades existents.
Redirecció d'afegir eixida en Bash
jpuigcerver@fp:~/psp$catstdout.txt
Aquesta informació s'imprimeix per stdoutjpuigcerver@fp:~/psp$echo"Aquesta informació s'afegeix al final">>stdout.txt
jpuigcerver@fp:~/psp$catstdout.txt
Aquesta informació s'imprimeix per stdoutAquesta informació s'afegeix al final
Aquest exemple comença a partir del exemple anterior, on es mostra el contingut
del fitxer stdout.txt.
Després, s'utilitza la comanda echo afegir una informació al final del fitxer
stdout.txt mitjançant la redirecció >>.
Finalment, es mostra el contingut del fitxer stdout.txt, amb la nova informació
al final del fitxer.
Redirecció error 2>: Crea un nou fitxer contenint l'eixida d'error
del programa executat. Atenció, si el fitxer existeix, aquest és sobreescrit
(i es perden les dades existents)
Redirecció d'error en Bash
jpuigcerver@fp:~/psp$ls
jpuigcerver@fp:~/psp$rminexistent
rm: cannot remove 'inexistent': No such file or directoryjpuigcerver@fp:~/psp$rminexistent2>stderr.txt
jpuigcerver@fp:~/psp$ls
stderr.txtjpuigcerver@fp:~/psp$catstderr.txt
rm: cannot remove 'inexistent': No such file or directory
Aquest exemple comença amb la comanda ls, que mostra els continguts del directori
actual, on es pot veure que està buit.
Després, s'executa rm, que intenta eliminar un fitxer anomenat "inexistent", el
qual no existeix. Com es veu en la imatge, aquesta comanda falla i mostra per pantalla
l'error (stderr).
Es torna a repetir la comanda anterior, però esta vegada redirigint
l'error al fitxer stderr.txt amb l'operador 2>.
Finalment, es mostra el contingut del fitxer stderr.txt, amb l'error anterior.
Redirecció afegir error 2>>: Afegeix (append) un fitxer l'eixida d'error.
Si el fitxer no existeix es crea. Les noves dades s'afegeixen al final del fitxer
i no s'eliminen les dades existents.
Redirecció d'afegir error en Bash
jpuigcerver@fp:~/psp$catstderr.txt
rm: cannot remove 'inexistent': No such file or directoryjpuigcerver@fp:~/psp$cdnoexisteix
bash: cd: noexisteix: No such file or directoryjpuigcerver@fp:~/psp$cdnoexisteix2>>stderr.txt
jpuigcerver@fp:~/psp$catstderr.txt
rm: cannot remove 'inexistent': No such file or directorybash: cd: noexisteix: No such file or directory
Aquest exemple comença a partir del exemple anterior, on es mostra el contingut
del fitxer stderr.txt.
Després, s'utilitza la comanda cd, que intenta accedir al directori noexisteix,
el qual no existeix. Com es veu en la imatge, aquesta comanda falla i mostra per pantalla
l'error (stderr).
Es torna a repetir la comanda anterior, però esta vegada redirigint
l'error al final del fitxer stderr.txt amb l'operador 2>>.
Finalment, es mostra el contingut del fitxer stdout.txt, amb el nou error
al final del fitxer.
Redirecció eixida i error &> i &>>: Funciona de la mateixa manera que
els operadors anteriors, amb la diferència que redirigeix els dos fluxos,
el d'eixida i el d'error.
Redirecció d'eixida i error en Bash
jpuigcerver@fp:~/psp$ls
jpuigcerver@fp:~/psp$echo"Aquesta informació s'imprimeix per stdout"&>out.txt
jpuigcerver@fp:~/psp$rminexistent&>>out.txt
jpuigcerver@fp:~/psp$catout.txt
Aquesta informació s'imprimeix per stdoutrm: cannot remove 'inexistent': No such file or directory
Aquest exemple comença amb la comanda ls, que mostra els continguts del directori
actual, on es pot veure que està buit.
Després, s'executa echo, on es redirigeix l'eixida (stdout) al fitxer
out.txt mitjançant l'operador &>.
A continuació, s'executa la comanda rm inexistent, on l'error d'aquesta també
es redirigeix al fitxer out.txt. En aquest cas, es gasta l'operador &>> per
afegir-ho al final.
Finalment, es mostra el contingut del fitxer out.txt, on es pot observar
que els operadors &> i &>> redirigeixen els dos fluxos: stdout i stderr.
Redirecció entrada <: Passa les dades d'un fitxer com a entrada estàndard
del programa.
Redirecció d'entrada en Bash
jpuigcerver@fp:~/psp$cattext.txt
Aquest es un text qualsevoljpuigcerver@fp:~/psp$traeiouAEIOU<text.txt
AqUEst Es Un tExt qUAlsevOl
Aquest exemple comença amb un fitxer de text que conté un text qualsevol.
Després, s'executa tr aeiou AEIOU, que tradueix totes les vocals minúscules
a vocals majúscules. Aquesta comanda pot rebre la informació des de l'entrada
estàndard (stdin). En aquest cas, li la passem des del fitxer text.txt
mitjançant la redirecció <.
Les canonades (o pipes) són un mecanisme per a la comunicació entre processos
utilitzant els fluxos de dades estàndard, de tal manera que el stdout de cada
process es passa al procés següent com a stdin.
Les canonades es representen mitjançant el símbol |.
Canonades en bash
Mostra els colors del fitxer colors.txt per stdout.
Quan un programa Java crea un procés fill, el procés pare pot
gestionar els fluxos de dades del fill per poder comunicar-se
amb ell o que aquest es comunique amb altres processos.
Per fer-ho, s'utilitzarà la classe Process,
que permet obtindre un objecte diferent per cada flux de dades:
Tots aquests objectes Stream, llegeixen i escriuen les dades en binari. Per facilitar la
gestió d'aquestes dades, existeixen les classes
InputStreamReader
i OutputStreamWriter
que treballen en caràcters en compte de bytes.
A més, aquests objectes poden ser combinats amb buffers, que emmagatzema les dades de manera
temporal i ens proporciona mètodes per facilitar la gestió d'aquestes dades.
BufferedReader
per llegir les dades i
BufferedWriter
per escriure'n.
També existeix la classe PrintWriter,
que permet escriure en un Stream amb mètodes similars als que ja coneixem: print, println,
printf,...
Aquest programa crea un nou procés utilitzant l'ordre definida
en la variable String[] program.
El procés és creat mitjançant la classe ProcessBuilder.
Una vegada creat, el procés pare espera a que acabe el procés fill
i imprimeix per pantalla el codi de retorn,
l'eixida estàndard (stdout) i l'error (stderr) que ha produït.
RunProcessOutput.java
packageud1.examples;importjava.io.IOException;importjava.util.Arrays;importjava.io.BufferedReader;importjava.io.InputStreamReader;publicclassRunProcessOutput{publicstaticvoidmain(String[]args){String[]program={"wsl","echo","Hello world!"};// String[] program = {"wsl", "rm", "inexistent"};ProcessBuilderpb=newProcessBuilder(program);try{Processprocess=pb.start();// Objectes per poder llegir l'eixida estàndard i l'errorBufferedReaderstdout=newBufferedReader(newInputStreamReader(process.getInputStream()));BufferedReaderstderr=newBufferedReader(newInputStreamReader(process.getErrorStream()));intcodiRetorn=process.waitFor();System.out.println("L'execució de "+Arrays.toString(program)+" ha acabat amb el codi: "+codiRetorn);Stringline;System.out.println("Stdout:");while((line=stdout.readLine())!=null)System.out.printf(" %s\n",line);System.out.println("Stderr:");while((line=stderr.readLine())!=null)System.out.printf(" %s\n",line);}catch(IOExceptionex){System.err.println("Excepció d'E/S:");System.err.println(ex.getMessage());System.exit(-1);}catch(InterruptedExceptionex){System.err.println("El procés fill ha finalitzat de manera incorrecta.");System.exit(-1);}}}
Exemple d'execució
String[] program = {"wsl", "echo", "Hola món!"}: El programa RunProcessOutput
executa la comanda echo "Hola món!", que mostra per pantalla el text "Hola món".
L'execució de [wsl, echo, Hola món!] ha acabat amb codi de retorn: 0
Stdout:
Hola món!
Stderr:
String[] program = {"wsl", "ls", "~"}: El programa RunProcessOutput
executa la comanda ls ~, que mostra els continguts del directori d'usuari.
L'execució de [wsl, ls, ~] ha acabat amb codi de retorn: 0
Stdout:
Desktop
Documents
Downloads
Music
Pictures
Videos
Stderr:
java RunProcessOutput rm inexistent: El programa RunProcessOutput executa la comanda
rm inexistent, que intenta eliminar un fitxer que no existeix. Es pot veure a la imatge que
mostra el mateix missatge d'error que la comanda original.
L'execució de [rm, inexistent] ha acabat amb codi de retorn: 1
Stdout:
Stderr:
rm: cannot remove 'inexistent': No such file or directory
Utilitzant l'esquema anterior, aquest programa, a més, li passa dades al procés fill
mitjançant l'entrada estàndard (stdin).
El procés és creat mitjançant la classe ProcessBuilder.
Una vegada creat, el procés pare llegeix des d'entrada estàndard (teclat)
i li passa aquestes dades al procès fill com a entrada estàndard (stdin).
Quan s'introdueix una línia en blanc, espera a que el fill acabe
i imprimeix per pantalla el codi de retorn,
l'eixida estàndard i l'error que ha produït.
RunProcessInput.java
packageud1.examples;importjava.util.Arrays;importjava.util.Scanner;importjava.util.Locale;importjava.io.IOException;importjava.io.BufferedReader;importjava.io.InputStreamReader;importjava.io.PrintWriter;publicclassRunProcessInput{publicstaticvoidmain(String[]args){String[]program={"wsl","tr","a","A"};ProcessBuilderpb=newProcessBuilder(program);try{Processprocess=pb.start();// Objecte per poder llegir l'entrada estàndard del programa pareScannerin=newScanner(System.in).useLocale(Locale.US);// Objecte per poder escriure a l'entrada estàndard del procés fillPrintWriterstdin=newPrintWriter(process.getOutputStream());System.out.println("Stdin:");Stringline;while(!(line=in.nextLine()).isEmpty())stdin.println(line);// Quan acabem de introduir dades, cal tancar el streamstdin.flush();stdin.close();// Objectes per poder llegir l'eixida estàndard i l'errorBufferedReaderstdout=newBufferedReader(newInputStreamReader(process.getInputStream()));BufferedReaderstderr=newBufferedReader(newInputStreamReader(process.getErrorStream()));intcodiRetorn=process.waitFor();System.out.println("L'execució de "+Arrays.toString(program)+" ha acabat amb el codi: "+codiRetorn);System.out.println("Stdout:");while((line=stdout.readLine())!=null)System.out.printf(" %s\n",line);System.out.println("Stderr:");while((line=stderr.readLine())!=null)System.out.printf(" %s\n",line);}catch(IOExceptionex){System.err.println("Excepció d'E/S.");System.err.println(ex.getMessage());System.exit(-1);}catch(InterruptedExceptionex){System.err.println("El procés fill ha finalitzat de manera incorrecta.");System.exit(-1);}}}
Exemple d'execució
String[] program = {"tr", "aeiou", "AEIOU"}:
El programa RunProcessInput executa la comanda tr aeiou AEIOU,
que traduirà totes les vocals minúscules del text que rep per
entrada estàndard a vocals majúscules.
Stdin:
Aquest es un text qualsevol
L'execució de [tr, aeiou, AEIOU] ha acabat amb codi de retorn: 0
Stdout:
AqUEst Es Un tExt qUAlsevOl
Stderr:
Una canonada (o pipe) consisteix en encadenar multiples programes, de tal manera que la eixida estàndard d'un
es passat al següent com a entrada estàndard.
packageud1.examples;importjava.io.IOException;importjava.io.BufferedReader;importjava.io.InputStreamReader;importjava.util.List;importjava.util.ArrayList;publicclassRunPipelineColors{publicstaticvoidmain(String[]args){ArrayList<ProcessBuilder>programs=newArrayList<>();programs.add(newProcessBuilder("wsl","cat","files/ud1/colors.txt"));programs.add(newProcessBuilder("wsl","sort"));programs.add(newProcessBuilder("wsl","uniq","-c"));programs.add(newProcessBuilder("wsl","sort","-r","-n"));programs.add(newProcessBuilder("wsl","head","-3"));try{List<Process>processes=ProcessBuilder.startPipeline(programs);for(Processp:processes)p.waitFor();Processlast=processes.getLast();// .get(processes.size() - 1);BufferedReaderstdout=newBufferedReader(newInputStreamReader(last.getInputStream()));Stringline;System.out.println("Stdout:");while((line=stdout.readLine())!=null)System.out.printf(" %s\n",line);}catch(IOExceptionex){System.err.println("Excepció d'E/S.");System.out.println(ex.getMessage());System.exit(-1);}catch(InterruptedExceptionex){System.err.println("El procés fill ha finalitzat de manera incorrecta.");System.exit(-1);}}}