I/O elementare Java IO elementare Prof. Francesco Bellotti ELIOS Lab - DIBE – The University of Genoa 1 Il package java.io Il linguaggio Java non ha istruzioni (statement) standard per fare l’input e output I/O fatto attraverso metodi (funzioni) che sono parte di un package Un package è una collezioni di classi che offrono funzionalità usabili da altri programmi Un package è come una scatola degli attrezzi con le classi che sono gli attrezzi Per fare l’I/O di base usiamo il package java.io, che è il più semplice Ne esistono anche altri più specialistici 2 I/O streams In Java, una sorgente di dati di input è detta un input stream e i dati in uscita sono detti output stream In generale, un programma può avere più stream di input e di output Per iniziare, ueseremo 3 semplici stream di IO System.in — lo stream di input System.out — lo stream di output normale System.err — lo stream di output per i messaggi di errore System.in è tipicamente collegato alla tastiera e i dati sono caratteri System.out e System.err sono collegati al monitor e i dati sono sempre caratteri 3 Input e output 4 Input & output stream 5 Esempio di IO import java.io.*; class Echo { public static void main (String[] args) throws IOException { //Analizzeremo in seguito queste 2 linee. //Per ora consideriamole necessarie per creare //l’oggetto stdin usato per leggere da tastiera InputStreamReader inStream = new InputStreamReader( System.in ) ; BufferedReader stdin = new BufferedReader( inStream ); String inData; C:\users\default>java Echo Enter the data: System.out.println("Enter the data:"); //legge una riga di codice dalla tastiera inData = stdin.readLine(); System.out.println("You entered:" + inData ); This is what the user enters You entered:This is what the user enters C:\users\default> } } 6 Analizzando il programma import java.io.*; avverte il compilatore di usare il package java.io Il simbolo * significa che ogni classe di quel package potrebbe essere usata throws IOException E’necessaria per programmi che fanno input (almeno per ora) Informa il compilatore che il metodo main() potrebbe fallire Se main() dovesse fallire, la Java Virtual Machine che interpreta il programma Java gestirà una “accettabile” chiusura del programma Le eccezioni (situazioni di possibile errore) o vengono gestite localmente in un metodo, oppure vengono rilanciate dal metodo ad altri metodi (i metodi chimanti) o alla virtual machine (come appunto in questo caso) 7 Creazione dell’oggetto per leggere da tastiera La variabile inStream è usata solo per connettere l’InputStreamReader al BufferedReader InputStreamReader inStream = new InputStreamReader( System.in ) ; BufferedReader stdin = new BufferedReader( inStream ); Si può semplificare il codice scrivendo una sola riga BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); 8 Convertire stringhe di caratteri in valori numerici Usando il programma Echo, se si inseriscono da tastiera dei valori numerici, questi sono letti come caratteri Verificalo! E se voglio leggere dei numeri? Devo trasformare i caratteri in numeri Usando i metodi della classe Integer, che è il wrapper del tipo int 9 Lettura di valori numerici import java.io.*; class EchoSquare { public static void main (String[] args) throws IOException { BufferedReader stdin = new BufferedReader (new InputStreamReader(System.in)); String inData; int num, square; // declare two int variables System.out.println("Enter an integer:"); inData = stdin.readLine(); num = Integer.parseInt( inData ); // convert inData to int square = num * num ; // compute the square System.out.println("The square of " + inData + " is " + square); } } 10 Convertire stringhe di caratteri in valori numerici Ovviamente, si può anche scrivere il valore direttamente nell’argomento num = Integer.parseInt( "39" ); E se l’utente del programma scrivesse un intero in formato sbagliato? 134 -45 Sono ok 1 4 9 2 14.92 centotrentquattro “ 134” Sono sbagliati Lo statement inData = stdin.readLine() non darebbe alcun problema Ma num = Integer.parseInt( inData ) non sarebbe in grado di interpretare la sequenza come un intero Il metodo parseInt() lancia un’eccezione di tipo NumberFormatException Enter an integer: 14.92 java.lang.NumberFormatException: 14.92 11 Esempio: somma di 2 interi import java.io.*; class AddTwo { public static void main (String[] args) throws IOException { BufferedReader stdin = new BufferedReader ( new InputStreamReader( System.in ) ); String line1, line2; int first, second, sum ; // declaration of input Strings // declaration of int variables System.out.println("Enter first integer:"); line1 = stdin.readLine(); first = Integer.parseInt( line1 ); // convert line1 to first int System.out.println("Enter second integer:"); line2 = stdin.readLine(); second = Integer.parseInt( line2 ); // convert line2 to second int sum = first + second; // add the two ints, put result in sum System.out.println("The sum of " + first + " plus " + second +" is " + sum ); } } 12 Esercizi di programmazione Riscrivi il programma in modo che poduca lo stesso output, ma senza usare nel println finale né la variabile first né la variabile second Scrivere un programma simile al precedente, che riceva dall’utente i valori di un dividendo e di un divisore interi e produca in output i risultati della divisione e del resto 13 Esercizi di programmazione Scrivere un programma che legga un numero di centesimi e scriva il numero di Euro e centesimi D:\users\default>java Dollars Inserisci il numero di centesimi: 324 Sono 3 euro e 24 centesimi Usa aritmetica intera e non floating point! If(num>100) – num = 24 else – num=0; 14 Esercizi di programmazione Il resto giusto Scrivere un programma che prenda in ingresso un numero di centesimi da restituire al cliente e produca in uscita il numero di monete da: 2 e 1 Euro, e da 50, 20, 10, 5, 2 e 1 centesimi da dare al cliente Usa aritmetica intera e non floating point! 15 Input floating point import java.io.*; class StringToDouble { public static void main (String[] args) { final String charData = "3.14159265"; double value; value = Double.parseDouble( charData ) ; System.out.println("value: " + value +" twice value: " + 2*value ); } } Cambierebbe qualcosa se togliessi le virgolette dall’inizializzazione di charData? E se invece usassimo la notazione scientifica? final String charData = "0.314159265E+1"; 16 Input floating point da tastiera import java.io.*; class InputToDouble { public static void main (String[] args) throws IOException { String charData; double value; BufferedReader stdin = InputStreamReader(System.in)); new BufferedReader (new System.out.println("Enter a double:"); charData = stdin.readLine(); value = Double.parseDouble( charData ) ; System.out.println("value: " + value +" twice value: " + 2*value ); } } 17 Il costo di una cena… import java.io.*; class RestaurantBill { public static void main (String[] args) throws IOException { String charData; double basicCost; BufferedReader stdin = new BufferedReader ( new InputStreamReader( System.in ) ); System.out.println("Enter the basic cost:"); charData = stdin.readLine(); basicCost = Double.parseDouble( charData ) ; System.out.println("basic cost: " + basicCost + " total cost: " + (basicCost + basicCost*0.06 + basicCost*0.20)); } } Il costo di una cena è dato dal costo di base (inserito dall’utente) + il 6% di tasse e il 20% di servizio 18 Esercizio di programmazione Modificare il programma precedente così che l’utente possa inserire da tastiera le percentuali per le tasse e il servizio 19 Java come una calcolatrice… import java.io.*; class SquareRoot { public static void main (String[] args) throws IOException { String charData; double value; // read in a double BufferedReader stdin = new BufferedReader (new InputStreamReader(System.in)); System.out.print ("Enter a double:"); charData = stdin.readLine(); value = Double.parseDouble( charData ) ; // calculate its square root double result = Math.sqrt( value ); // write out the result System.out.println("square root: " + result ); } } 20 La classe Math La classe Math ha molti metodi che possono tornare utili… Es: log, sin, cos Provali per esercizio Vuoi saperne di più sulla classe Math? Controlla la documentazione Java online: java.sun.com oppure sul tuo java sdk! Sqrt è descritto così: static double sqrt(double a) Qual è il tipo di input? E quale quello di output? Prova l’esercizio precedente con vari input Es. 3.5, 9.0, 9, -4, etc. 21 Conversione automatica di tipo Sqrt() si aspetta un double come parametro di ingresso. Tuttavia il codice funziona anche se noi gli passiamo un intero Il compilatore inserisce automaticamente il codice per la conversione al tipo giusto Alla chiamata di sqrt() il parametro passato è di tipo double Spesso i programmatori usano un cast esplicito: int x = 9; System.out.println( Math.sqrt( (double)x ) ); Come detto, in questo caso il cast non era richiesto Qual è il risultato di questo frammento? int x = 1; int y = 9; System.out.println( Math.sqrt(x/y) ) ); Il risultato è 0.0, forse non quello che ci saremmo aspettati. Come possiamo risolvere la cosa? Con un cast esplicito 22 Math.cos() e Math.sin() vogliono radianti… Ma noi siamo abituati a ragionare in gradi… Usiamo le funzioni di Math public static double toRadians(double angdeg) public static double toDegrees(double angrad) import java.io.*; class CosineCalc { public static void main (String[] args) throws IOException { String charData; double degrees; // read in a double BufferedReader stdin = new BufferedReader (new InputStreamReader(System.in)); System.out.print ("Enter degrees:"); charData = stdin.readLine(); degrees = Double.parseDouble( charData ) ; // calculate its cosine double result = Math.cos( Math.toRadians(degrees) ); //Nota le funzioni annidate // write out the result System.out.println("cosine: " + result ); } } 23 Esercizi di programmazione Scrivere un programma che calcola la velocità (ad un istante che l’utente specifica in input) di un oggetto lasciato cadere da una torre Usa la formula: v = (1/2) g t2 Scrivere un programma che il logaritmo in base 2 di un numero specificato dall’utente Ricorda: log2 X = (loge X) / (loge 2) 24 Esercizi di programmazione Scrivere un programma che legge da input 2 numeri e ne produce la media aritmetica e la media armonica Formula per la media armonica: H = 2 / ( 1/X + 1/Y ) 25 La gerarchia di classi di java.io 2 gerarchie di classi principali Basate sul tipo di dato su cui operano Character streams (16 bit) – Java.io.Reader e java.io.writer sono le superclassi abstract Byte streams (8 bit) – Java.io.InputStream e java.io.OutputStream 26 Reading and writing… Reader int read() int read(char cbuf[]) int read(char cbuf[], int offset, int length) Writer int write(int c) int write(char cbuf[]) int write(char cbuf[], int offset, int length) InputStream int read() int read(byte cbuf[]) int read(byte cbuf[], int offset, int length) OutputStream int write(int c) int write(byte cbuf[]) int write(byte cbuf[], int offset, int length) 27 The java.io jungle… 28 Using the streams I/O Streams Type of I/O Streams CharArrayReader CharArrayWriter ByteArrayInputStream ByteArrayOutputStream Use these streams to read from and write to memory. You create these streams on an existing array and then use the read and write methods to read from or write to the array. StringReader StringWriter StringBufferInputStream Use StringReader to read characters from a String in memory. Use StringWriter to write to a String. StringWriter collects the characters written to it in a StringBuffer, which can then be converted to a String. StringBufferInputStream is similar to StringReader, except that it reads bytes from a StringBuffer. FileReader FileWriter FileInputStream FileOutputStream Collectively called file streams, these streams are used to read from or write to a file on the native file system. The section How to Use File Streams. has an example that uses FileReader and FileWriter to copy the contents of one file into another. Memory File Description 29 Using the streams Data Conversion N/A DataInputStream DataOutputStream Read or write primitive data types in a machine-independent format. See How to Use DataInputStream and DataOutputStream. shows an example of using these two streams. Counting LineNumberReader LineNumberInputStream Keeps track of line numbers while reading. Printing PrintWriter PrintStream Contain convenient printing methods. These are the easiest streams to write to, so you will often see other writable streams wrapped in one of these. Buffering BufferedReader BufferedWriter BufferedInputStream BufferedOutputStream Buffer data while reading or writing, thereby reducing the number of accesses required on the original data source. Buffered streams are typically more efficient than similar nonbuffered streams and are often used with other streams. InputStreamReader OutputStreamWriter A reader and writer pair that forms the bridge between byte streams and character streams. An InputStreamReader reads bytes from an InputStream and converts them to characters, using the default character encoding or a character encoding specified by name. An OutputStreamWriter converts characters to bytes, using the default character encoding or a character encoding specified by name and then writes those bytes to an OutputStream. You can get the name of the default character encoding by calling System.getProperty("file.encoding"). Converting between Bytes and Characters 30 Reading/writing files import java.io.*; public class FileCopy { public static void main(String[] args) throws IOException { File inputFile = new File("farrago.txt"); //File inputFile = new File("C:\\farrago.txt"); File outputFile = new File("outagain.txt"); FileReader in = new FileReader(inputFile); FileWriter out = new FileWriter(outputFile); int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close(); } } 31 DataStreams (output) // write the data out DataOutputStream out = new DataOutputStream(new FileOutputStream("invoice1.txt")); double[] prices = { 19.99, 9.99, 15.99, 3.99, 4.99 }; int[] units = { 12, 8, 13, 29, 50 }; String[] descs = { "Java T-shirt", "Java Mug", "Duke Juggling Dolls", "Java Pin", "Java Key Chain" }; for (int i = 0; i < prices.length; i ++) { out.writeDouble(prices[i]); out.writeChar('\t'); out.writeInt(units[i]); out.writeChar('\t'); out.writeChars(descs[i]); out.writeChar('\n'); } out.close(); 32 DataStreams (input) // read it in again DataInputStream in = new DataInputStream(new FileInputStream("invoice2.txt")); double price; int unit; StringBuffer desc; double total = 0.0; try { while (true) { price = in.readDouble(); in.readChar(); // throws out the tab unit = in.readInt(); in.readChar(); // throws out the tab char chr; desc = new StringBuffer(20); //char lineSep = System.getProperty("line.separator").charAt(0); char lineSep = '\n'; while ((chr = in.readChar()) != lineSep) desc.append(chr); //String descStr = in.readLine(); System.out.println("You've ordered " + unit + " units of " + desc + " at $" + price); //System.out.println("You've ordered " + unit + " units of " + descStr + " at $" + price); total = total + unit * price; } } catch (EOFException e) { System.out.println("EOF reached!"); } System.out.println("For a TOTAL of: $" + total); in.close(); } 33