Entrada y salida (I / O)

52

Transcript of Entrada y salida (I / O)

Entrada y salida (I / O)� import java.io.*� Crear un objeto File para obtener información sobre un archivo en el

drive.� Esto no crea un nuevo archivo en el disco duro.

File f = new File(“example.txt”);if (f.exists() && f.length() > 1000) {

f.delete();}

Universidad de Sonora 2

Entrada y salida (I / O)canRead() Regresa true si el archivo puede ser leídodelete() Elimina el archivo del discoexists() Regresa true si el archivo existegetName() Regresa el nombre del archivolength() Regresa el número de bytes en el archivorenameTo(file) Cambia el nombre del archivo

Universidad de Sonora 3

Leer archivos� Para leer un archivo, pasar un File al construir un Scanner.

Scanner name = new Scanner(new File(“file name”));� Ejemplo en dos líneas:

File file = new File(“mydata.txt”);Scanner input = new Scanner(file);

� Ejemplo en una línea:Scanner input = new Scanner(new File(“mydata.txt”));

Universidad de Sonora 4

Caminos (paths) de archivos� Camino absoluto: el camino es con respecto al directorio raíz “/”.

C: /Documents/smith/hw6/input/data.csv� Windows usa barras invertidas para separar carpetas.� Camino relativo: el camino es con respecto al directorio actual:

superior.datentrada/kinglear.txt../datos/star.txt

� Es relativo al directorio actual.� Por ejemplo:

Universidad de Sonora 5

Caminos (paths) de archivosScanner input = new Scanner (new File("datos/readme.txt"));

� Si el programa está en H:/hw6� Scanner buscará H:/hw6/data/readme.txt

Universidad de Sonora 6

Errores de compilador con archivosimport java.io.*; // para Fileimport java.util.*; // para Scannerpublic class ReadFile {

public static void main(String[] args){

Scanner input = new Scanner(new File(“data.txt”));String text = input.next();System.out.println(text);

}}

Universidad de Sonora 7

Errores de compilador con archivos� El programa no compila por el siguiente error:

ReadFile.java:6: unreported exceptionjava.io.FileNotFoundException;

must be caught or declared to be thrownScanner input = new Scanner(new File(“data.txt”));

^� Se necesita encerrar esa línea entre try / catch.� Es un ejemplo de una excepción marcada (checked exception).

Universidad de Sonora 8

Tokens de entrada� Token: unidad léxica separada por espacios en blanco.� Un Scanner divide el contenido de un archivo en tokens.� Si un archivo contiene lo siguiente:

� Un Scanner puede interpretar los tokens como los siguientes tipos:

Universidad de Sonora 9

Token Tipo23 int, double, String3.14 double, String“John Smith” String

Cursor de entrada� Considerar un archivo weather1.txt con el siguiente texto:

� Un Scanner ve toda entrada como un flujo de caracteres.

� Cursor de entrada: es la posición actual del Scanner. Apunta al siguiente token que se va a leer.

Universidad de Sonora 10

Consumiendo tokens� Consumir la entrada: leer de la entrada y avanzar el cursor.� Llamar a nextInt, etc. mueve el cursor después del token actual.

Universidad de Sonora 11

Ejemplo de archivos� Dado el archivo de entrada weather1.txt:

� Escribir un programa que imprima el cambio de temperatura entre cada par de días vecinos.

� 16.2 a 23.5, cambio = 7.3� 23.5 a 19.1, cambio = -4.4� 19.1 a 7.4, cambio = -11.7� 7.4 a 22.8, cambio = 15.4� Etc.

Universidad de Sonora 12

Solución// Despliega cambios en la temperatura de los datos en un archivo de

entrada.import java.io.*; // for Fileimport java.util.*; // for Scannerpublic class Temperatures {

public static void main(String[] args) throws FileNotFoundException{

Scanner input = new Scanner(new File(“weather1.txt”));double prev = input.nextDouble(); // fencepost

Universidad de Sonora 13

Soluciónfor (int i = 1; i <= 7; i++) {

double next = input.nextDouble();System.out.println(prev + “ a ” + next + “, change = ” +

(next - prev));prev = next;

}}

}

Universidad de Sonora 14

Leer un archivo entero� Suponer que se quiere que el programa funcione sin importar cuántos

números haya en el archivo.� Actualmente, si el archivo tiene más números, no se leerán.� Si el archivo tiene menos números, ¿qué pasará?� Salida de ejemplo de un archivo con solo 3 números:

Universidad de Sonora 15

Leer un archivo entero16.2 to 23.5, change = 7.323.5 to 19.1, change = -4.4Exception in thread “main”java.util.NoSuchElementExceptionat java.util.Scanner.throwFor(Scanner.java:838)at java.util.Scanner.next(Scanner.java:1347)at Temperatures.main(Temperatures.java:12)

Universidad de Sonora 16

Excepciones de Scanner� NoSuchElementException� Se leyó después del fin del archivo.� InputMismatchException� Se leyó en tipo erróneo de token (e.g. leyó “hi” como un int).

Universidad de Sonora 17

Excepciones de Scanner� Encontrando y arreglando esas excepciones:� Leer el texto de la excepción buscando las líneas del código fuente.� La primera línea que menciona el archivo; por lo general cerca del

fondo.Exception in thread “main”java.util.NoSuchElementExceptionat java.util.Scanner.throwFor(Scanner.java:838) at java.util.Scanner.next(Scanner.java:1347) at MyProgram.myMethodName(MyProgram.java:19) at MyProgram.main(MyProgram.java:6)

Universidad de Sonora 18

Pruebas de Scanner por entradas válidas

� Estos métodos de Scanner no consumen entrada; solo dan información sobre cuál será el próximo token.

� Útiles para ver qué información viene y para evitar excepciones.� Estos métodos también se pueden utilizar con un Scanner de consola.� Cuando se les llama desde la consola, a veces hacen una pausa

esperando una entrada.

Universidad de Sonora 19

hasNext() Devuelve true si hay un siguiente tokenhasNextInt() Devuelve true si hay un token siguiente y se puede leer como un inthasNextDouble() Devuelve true si hay un token siguiente y se puede leer como un double

Uso de métodos hasNext� Evitar errores de coincidencia de tipos:

Scanner console = new Scanner(System.in);System.out.print(“¿Cuál es tu edad? ”);if (console.hasNextInt()) {

int age = console.nextInt(); // funcionaSystem.out.println(“Hey, ” + age + “ es mucho”);

}else {

System.out.println(“No escribiste un entero.”);}

Universidad de Sonora 20

Uso de métodos hasNext� Evitar leer más allá del final de un archivo:

Scanner input = new Scanner(new File(“example.txt”));if (input.hasNext()) {

String token = input.next(); // funcionaSystem.out.println(“El siguiente token es ” + token);

}

Universidad de Sonora 21

Ejemplo de archivos 2� Modificar el programa de temperatura para procesar todo el archivo,

independientemente de cuántos números contenga.� Ejemplo: si se agregan los datos de un noveno día, la salida debe ser:

16.2 a 23.5, cambio = 7.323.5 a 19.1, cambio = -4.419.1 a 7.4, cambio = -11.77.4 a 22.8, cambio = 15.422.8 a 18.5, cambio = -4.318.5 a -1.8, cambio = -20.3-1.8 a 14.9, cambio = 16.714.9 a 16.1, cambio = 1.2

Universidad de Sonora 22

Solución 2// Despliega los cambios de temperatura de los datos de un archivo de

entrada.import java.io.*; // for Fileimport java.util.*; // for Scannerpublic class Temperatures {

public static void main(String[] args) throws FileNotFoundException{

Scanner input = new Scanner(new File(“weather1.txt”));double prev = input.nextDouble(); // fencepost

Universidad de Sonora 23

Solución 2while (input.hasNextDouble()) {

double next = input.nextDouble();System.out.println(prev + “ a ” + next + “, cambio = ” +

(next - prev));prev = next;

}}

}

Universidad de Sonora 24

Ejemplo de archivos 3� Modificar el programa de temperatura para manejar archivos que

contienen tokens no numéricos (saltándolos).� Por ejemplo, debe producir la misma salida que antes cuando se le da

este archivo de entrada, weather2.txt:

� Puede suponerse que el archivo comienza con un número.

Universidad de Sonora 25

Solución 3// Despliega los cambios de temperatura de los datos de un archivo de entrada.

import java.io.*; // for Fileimport java.util.*; // for Scannerpublic class Temperatures {

public static void main(String[] args) throws FileNotFoundException{

Scanner input = new Scanner(new File(“weather2.txt”));double prev = input.nextDouble(); // fencepost

Universidad de Sonora 26

Solución 3while (input.hasNext()) {

if (input.hasNextDouble()) {double next = input.nextDouble();System.out.println(prev + “ a ” + next + “, cambio = ” +

(next - prev));prev = next;

} else {input.next(); // tira los tokens no deseados

}} }

Universidad de Sonora 27

Ejemplo horas� Dado un archivo hours1.dat con el siguiente contenido:

123 Kim 12.5 8.1 7.6 3.2456 Eric 4.0 11.6 6.5 2.7 12789 Stef 8.0 8.0 8.0 8.0 7.5

� Considerar la tarea de calcular las horas trabajadas por cada persona:Kim (ID#123) trabajó 31.4 horas (7.85 horas/día)Eric (ID#456) trabajó 36.8 horas (7.36 horas/día)Stef (ID#789) trabajó 39.5 horas (7.9 horas/día)

� Intentemos resolver este problema token por token...Universidad de Sonora 28

Solución defectuosa// ¡Esta solución no funciona!import java.io.*; // para Fileimport java.util.*; // para Scannerpublic class HoursWorked {

public static void main(String[] args)throws FileNotFoundException

{Scanner input = new Scanner(new File(“hours1.dat”));

Universidad de Sonora 29

Solución defectuosawhile (input.hasNext()) {

int id = input.nextInt(); // procesa una personaString name = input.next();double totalHours = 0.0; int days = 0;while (input.hasNextDouble()) {

totalHours += input.nextDouble();days++;

}System.out.println(name + “ (ID#” + id + “) trabajó ” + totalHours +

“ horas (” + (totalHours / days) + “ hours/day)”);} } }

Universidad de Sonora 30

Solución defectuosaSusan (ID#123) worked 487.4 hours (97.48 hours/day)Exception in thread “main”java.util.InputMismatchException

at java.util.Scanner.throwFor(Scanner.java:840)at java.util.Scanner.next(Scanner.java:1461)at java.util.Scanner.nextInt(Scanner.java:2091)at HoursWorked.main(HoursBad.java:9)

� El ciclo interno while toma la identificación de la siguiente persona.� Se quiere procesar los tokens, pero los saltos de línea importan porque

marcan el final de los datos de una persona.Universidad de Sonora 31

Scanner basado en líneas

Scanner input = new Scanner(new File(“file name”));while (input.hasNextLine()) {

String line = input.nextLine();process this line;

}

Universidad de Sonora 32

nextLine() Devuelve la siguiente línea completa de entrada (desde el cursor hasta \n)hasNextLine() Devuelve true si hay más líneas de entrada para leer (siempre es cierto para

la entrada de la consola)

Consumiendo líneas de entrada23 3.14 John Smith “Hello” world

45.2 19� El Scanner lee las líneas como sigue:

� Cada caracter \n se consume pero no se regresa.

Universidad de Sonora 33

Scanner sobre strings� Un Scanner puede tokenizar el contenido de un String:

Scanner name = new Scanner(String);

Universidad de Sonora 34

Scanner sobre strings� Ejemplo:

String text = “15 3.2 hello 9 27.5”;Scanner scan = new Scanner(text);int num = scan.nextInt();System.out.println(num); // 15double num2 = scan.nextDouble();System.out.println(num2); // 3.2String word = scan.next();System.out.println(word); // hello

Universidad de Sonora 35

Mezclando líneas y tokens

Universidad de Sonora 36

Archivo input.txt Salida en la consolaThe quick brown fox jumps overthe lazy dog.

La línea tiene 6 palabrasLa línea tiene 3 palabras

Mezclando líneas y tokens// Cuenta las palabras de cada línea de un archivoScanner input = new Scanner(new File(“input.txt”));while (input.hasNextLine()) {

String line = input.nextLine();Scanner lineScan = new Scanner(line);// procesa el contenido de esta líneaint count = 0;while (lineScan.hasNext()) {

String word = lineScan.next();count++;

}System.out.println(“La línea tiene ” + count + “ palabras”);

}Universidad de Sonora 37

Ejemplo horas� Con esto, ya se puede arreglar el ejemplo.

Universidad de Sonora 38

Solución horas correcta// Procesa un archivo de empleados e imprime las horas de cada empleadoimport java.io.*; // for Fileimport java.util.*; // for Scannerpublic class Hours {

public static void main(String[] args) throws FileNotFoundException {Scanner input = new Scanner(new File(“hours.txt”));while (input.hasNextLine()) {

String line = input.nextLine();Scanner lineScan = new Scanner(line);int id = lineScan.nextInt(); // e.g. 456String name = lineScan.next(); // e.g. Eric

Universidad de Sonora 39

Solución horas correctadouble sum = 0.0;int count = 0;while (lineScan.hasNextDouble()) {

sum = sum + lineScan.nextDouble();count++;

}double average = sum / count;System.out.println(name + “ (ID#” + id + “) worked ” +

sum + “ hours (” + average + “ hours/day)”);}

}}

Universidad de Sonora 40

Salida a archivos� PrintStream: un objeto en el paquete java.io que le permite imprimir la

salida a un destino como un archivo.� Cualquier método utilizado en System.out (como print, println) funciona

en un PrintStream.� Sintaxis:

PrintStream name = new PrintStream(new File(“file name”));� Ejemplo:

PrintStream output = new PrintStream(new File(“out.txt”)); output.println(“Hello, file!”);output.println(“This is a second line of output.”);

Universidad de Sonora 41

Detalles sobre PrintStream� Si el archivo dado no existe, se crea.� Si el archivo dado ya existe, se sobrescribe.� La salida que imprime aparece en un archivo, no en la consola.� Se tiene que abrir el archivo con un editor para verlo.� No se debe abrir el mismo archivo para leer (Scanner) y escribir

(PrintStream) al mismo tiempo.� El archivo se va a sobrescribir con un archivo vacío (0 bytes).

Universidad de Sonora 42

System.out y PrintStream� El objeto de salida de la consola, System.out, es un PrintStream.

PrintStream out1 = System.out;PrintStream out2 = new PrintStream(new File(“data.txt”)); out1.println(“Hello, console!”); // va a la consolaout2.println(“Hello, file!”); // va al archivo

� Se puede guardar una referencia a System.out en una variable PrintStream.

� La impresión en la variable hace que aparezca la salida en la consola.� Se puede pasar System.out a un método como PrintStream.� Permite que un método envíe salida a la consola o un archivo.

Universidad de Sonora 43

Ejemplo con PrintStream� Modificar el programa de horas para usar un PrintStream para enviar la

salida al archivo hours_out.txt.� El programa no producirá salida de consola.� El archivo hours_out.txt se creará con el texto:

Kim (ID#123) trabajó 31.4 horas (7.85 horas/día)Eric (ID#456) trabajó 36.8 horas (7.36 horas/día)Stef (ID#789) trabajó 39.5 horas (7.9 horas/día)

Universidad de Sonora 44

Solución con PrintStream// Procesa un archivo de empleados e imprime las horas de cada empleado

import java.io.*; // for Fileimport java.util.*; // for Scannerpublic class Hours {

public static void main(String[] args) throws FileNotFoundException {Scanner input = new Scanner(new File(“hours.txt”));PrintStream out = new PrintStream(new File(“hours_out.txt”));while (input.hasNextLine()) {

String line = input.nextLine();Scanner lineScan = new Scanner(line);int id = lineScan.nextInt(); // e.g. 456String name = lineScan.next(); // e.g. Eric

Universidad de Sonora 45

Solución con PrintStreamdouble sum = 0.0;int count = 0;while (lineScan.hasNextDouble()) {

sum = sum + lineScan.nextDouble();count++;

}double average = sum / count;out.println(name + “ (ID#” + id + “) worked ” +

sum + “ hours (” + average + “ hours/day)”);}

}}

Universidad de Sonora 46

Solicitar un nombre de archivo� Se le puede pedir al usuario que indique el archivo a leer.� Si el nombre del archivo puede tener espacios, usar nextLine(), no

next().// Solicita el nombre del archivoScanner console = new Scanner(System.in);System.out.print(“Escriba el nombre del archivo de entrada: ”);String filename = console.nextLine();Scanner input = new Scanner(new File(filename));

� La clase File tiene un método exists() para revisar si el archivo existe.

Universidad de Sonora 47

Revisa si el archivo existeFile file = new File(filename);if (!file.exists()) {

// intenta otro archivo de entrada como respaldoSystem.out.print(“El archivo ” + filename + “ no existe”);file = new File(“hours1.dat”);

}

Universidad de Sonora 48

Mezclando tokens y líneas� El uso de nextLine junto con los métodos basados en tokens en el

mismo Scanner puede generar resultados no esperados.23 3.14Joe “Hello” world

45.2 19� Uno pensaría que puede leer 23 y 3.14 con nextInt y nextDouble, luego

leer Joe “Hello” world con nextLine.System.out.println(input.nextInt()); // 23System.out.println(input.nextDouble()); // 3.14System.out.println(input.nextLine()); //

Universidad de Sonora 49

Mezclando tokens y líneas� La llamada a nextLine produce un string vacío. ¿Por qué?� nextDouble no consume el fin de línea (caracter \n).

Universidad de Sonora 50

Ejemplo de línea y tokenScanner console = new Scanner(System.in);System.out.print(“Enter your age: ”);int age = console.nextInt();System.out.print(“Now enter your name: ”);String name = console.nextLine();System.out.println(name + “ is ” + age + “ years old.”);

Universidad de Sonora 51

Ejemplo de línea y token

� Conclusión: No hay que leer tokens y líneas del mismo Scanner.

Universidad de Sonora 52