I/O desde la linea de Comandos Los programas normalmente tienen funcionalidades para el ingreso o captura de datos desde la linea de comandos. La plataforma Java soporta estas iteracciones de dos formas: a través de los Streams estándar o a través de la clase Console. 1. Estándar Streams. Los Streams estándar son una característica de muchos sistemas operativos. Por defecto, leen la entrada del teclado y escriben la salida en pantalla. También soportan I/O en archivos y I/O entre programas. La plataforma Java soporta 3 Streams estandar, estos son: La entrada estandar (Standard Input), lograda mediante System.in; La salida estandar (Standard Output) lograda medienta System.out; y el Stream de error estandar, lograda mediante System.err. Estos objetos son definidos automáticamente y no necesitan ser abiertos para su utilización. Los Streams para la entrada y el error estandar son solo de escritura, separar la salida y error estandar brinda la posibilidad de escribir en un archivo y poder controlar los errores por separado. Los Streams estandar “no son” streams orientados a Carácter, son Streams orientados a byte. System.out y System.err se definen como objetos de PrintStream. Por el contrario System.in es un byte Stream sin caracteristicas de character Stream. Para utilizar la entrada estandar como un Stream Carácter, se debe envolver (wrap) en un InputStreamReader así: InputStreamReader cin = new inputStreamReader(System.in); 1.1 Lectura de consola. [1] La entrada de consola la obtenemos leyendo de System.in. Para conseguir un flujo de caracteres envolvemos (wrapping) dicha clase en un objeto del tipo BufferedReader, esto para que nuestro flujo soporte un buffer, asi se logra mas eficiencia. Atendiendo a las especificaciones de la clase BufferedReader, el parámetro que se le pasa al constructor debe ser un stream de entrada del tipo Reader (Reader es abstracto), recurriremos a una de sus subclases (que implementan Reader), puede ser InputStreamReader que convierte bytes a caracteres. Otra vez más, atendiendo a la especificación de InputStreamReader el parámetro que se le pasa es de tipo InputStream, o sea, la entrada orientada a byte que en este caso es System.in. De esta manera se ha asociado un dispositivo físico (el teclado) a un stream orientado a caracteres mediante el wrapping de la clase System con la clase BufferedReader. Resumiendo: 1. BufferedReader (Reader input); clase que recibe un flujo de caracteres de entrada. El buffer que queremos crear recibe un flojo de caracteres de entrada. 2. InputStreamReader ( InputStream input2) ; clase que convierte de byte a carácter. El flujo de caracteres recibe un flujo en su entrada. 3. BufferedReader br = new BufferedReader(new InputStreamReader(Sys­ tem.in); br es un Character Stream que se linka a la consola a traves de la clase System.in la cual hemos tenido que wrappear para convertir de byte a char. Ejemplo 1. Lectura de consola. //En este ejemplo leemos de consola cadenas de caracteres. import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; public class LecturaStringConsola { public static void main(String args[]) throws IOException { String cadena; BufferedReader br; //Creamos un BufferedReader a trevés de System.in br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Empieza a escribir, 'stop' para salir"); //leemos cadena de caracteres mediante readLine(). do { cadena = br.readLine(); System.out.println(cadena); } while(!cadena.equals("stop")); } }//Fin LecturaStringConsola 1.2 Imprimir a consola [1]. Hasta el momento para imprimir se ha utilizado la clase System.out pero en una aplicación más formal haremos uso de la clase PrintWriter, ya que esta soporta flujos de caracteres. PrintWriter brinda los métodos print() y println() para todos los tipos de datos a imprimir, por lo que se podrán usar igual que con System.out. Si un argumento pasado no es de un tipo simple (osea un objeto propio), entonces, los métodos de PrintWriter llaman al método toString() del objeto propio y luego imprimen el resultado. Ejemplo 2. Imprimir a pantalla. //En el siguiente ejemplo básico imprimimos a consola diferentes tipos de datos primitivos. import java.io.PrintWriter; public class Imprimir { public static void main(String args[]) { /* El constructor toma como parámetros un objeto de tipo OutputStream del cual deriva PrintStream, por tanto, ya tenemos linkada la clase con el dispositivo de salida (la consola). */ PrintWriter pw = new PrintWriter(System.out, true); pw.println("Imprime una cadena de texto"); int i = 15; pw.println("Imprime un entero " + i); double d = 6.8e-9; pw.println("Imprime un double " + d); } } Podemos definir métodos propios en nuestras aplicaciones para crear el PrintWriter, pueden ser salidas propias a archivos, sockets, etc. 2. La consola Un modo avanzado de los Streams estandar es la consola (clase Console), este es un objeto predefinido del tipo Console y tiene la mayoria de las caracteristicas ofrecidas por los Streams estandar, ademas de otras. El objeto Console proporciona los Streams de entrada y salida orientados a Streams de carácter, con metodos de escritura y lectura (reader y writer). Antes de poder usar el objeto consola, se debe recuperar el objeto por medio de la invocación del metodo System.console(), el objeto Console es retornado siempre que este disponible, de lo contrario se retorna el valor de null. En ocasiones el objeto no esta disponible por que el OS (sistema operativo) no lo soporta, o por que la aplicación no fue ejecutada en un ambiente interactivo. El objeto consola ofrece el metodo readPassword para el ingreso de password de una forma segura, el metodo suprime el echo en la consola, asi que no se ven las teclas digitadas y segundo retorna es una arreglo de caracteres (Array) y no un String de caracteres, con lo que se logra destruirla de memoria tan pronto sea necesario. Su uso se ilustra con el siguiente ejemplo: import java.io.Console; import java.util.Arrays; import java.io.IOException; public class Password { public static void main (String args[]) throws IOException { Console c = System.console(); if (c == null) { System.err.println("No console."); System.exit(1); } String login = c.readLine("Enter your login: "); char [] oldPassword = c.readPassword("Enter your old password: "); if (verify(login, oldPassword)) { boolean noMatch; do { char [] newPassword1 = c.readPassword("Enter your new password: "); char [] newPassword2 = c.readPassword("Enter new password again: "); noMatch = ! Arrays.equals(newPassword1, newPassword2); if (noMatch) { c.format("Passwords don't match. Try again.%n"); } else { change(login, newPassword1); c.format("Password for %s changed.%n", login); } Arrays.fill(newPassword1, ' '); Arrays.fill(newPassword2, ' '); } while (noMatch); } Arrays.fill(oldPassword, ' '); } // Metodo no desarrollado. static boolean verify(String login, char[] password) { return true; } //Metodo no desarrollado. static void change(String login, char[] password) {} } El programa sigue los siguientes pasos. 1. Instrucciones para recuperar el objeto consola, si el objeto no esta disponible abandona el programa. Console c = System.console(); if (c == null) { System.err.println("No console."); System.exit(1); } 2. Llamado al metodo Console.readLine para leer el login del usuario login = c.readLine("Enter your login: "); 3. Llamado al metodo Console.readPassword para leer la contraseña actual del usuario. 4. Verificación del password en el if. verify(login, oldPassword) 5. ETC. [1] Leo Suarez, http://www.javahispano.com