Visualizzazione dei risultati da 1 a 9 su 9
  1. #1

    System.in.read() come funziona?

    Salve, vorrei fare chiarezza a proposito dei metodi di input da tastiera, in particolare System.in.read() che ha un comportamento anomalo sul quale ho potuto soltanto fare ipotesi...

    Ho questa semplice classe che mi chiede di indovinare una lettera (q nel caso):
    codice:
    class InRead {   
    	public static void main(String args[]) throws java.io.IOException {
    		char ch; 
     
    		do { 
    			System.out.print("Premi un tasto seguito da INVIO: "); 
    
    
    			do { 
    				ch = (char) System.in.read();
    				
    			} while(ch == '\n' | ch == '\r');
    
    
    		} while(ch != 'q'); 
    	}   
    }
    Siccome la pressione di INVIO produce due escape, ho bisogno di un do/while "inner" per evitare che, non essendo l'escape == q, mi ristampi il print tre volte (una per la lettera digitata, due per gli escape).
    Funziona, ma mi chiedo come!
    Spiego le mie perplessità. Immaginiamo di digitare f e poi INVIO. InRead che fa? Analizza f, vede che non è \n né \r, esce dal do/while "inner" e passa al do/while esterno, dove, non verificando la condizione, torna a stampare il print! Quando analizza \n e \r?
    Ho avanzato l'ipotesi che l'immissione dell'input avvenga in modalità LIFO, per cui ci dovrebbe essere un buffer che inizi a "svuotarsi" processando i dati dall'ultimo inserito (INVIO coi suoi escape) tenendo per ultima la f. E' così?

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da Gas75 Visualizza il messaggio
    in particolare System.in.read() che ha un comportamento anomalo
    System.in è un InputStream e read() legge 1 byte. Questi sono i byte così come sono che la console (o chi per essa) invia.
    Pertanto se l'input arriva da una "vera" console (del S.O.), ricevi tutti i byte uno per uno, compresa la sequenza di newline, che può essere (sui Windows) CR + LF.

    C'è solo un piccolo dettaglio: lo standard-input da una "vera" console di norma è "bufferizzato". Vuol solo dire che l'input non è diretto a basso livello dalla console. E tra l'altro l'input arriva alla applicazione solo quando l'utente preme invio.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  3. #3
    Certo, di premere INVIO è chiesto esplicitamente, sennò non va avanti.
    Il programma l'ho lanciato da prompt.
    Quello che mi chiedo è come faccia a "gestire gli escape" (2° e 3° byte) dopo che ha gestito il char (1° byte), stando al codice.

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da Gas75 Visualizza il messaggio
    Certo, di premere INVIO è chiesto esplicitamente, sennò non va avanti.
    No, forse non hai compreso. Da una "vera" console l'input arriva alla applicazione SOLO quando l'utente preme invio.

    Se dalla console scrivi "pippo", (5 caratteri 'p' 'i' 'p' 'p' 'o'), questi NON arrivano subito alla applicazione. Solo quando premi invio allora la applicazione riceve in blocco, velocemente, 'p' 'i' 'p' 'p' 'o' CR LF

    Prova questo:

    codice:
    public class Prova {
        public static void main(String[] args) throws Exception {
            int v;
            do {
                v = System.in.read();
                System.out.println(v);
            } while (v != -1);
        }
    }

    Digita pippo e poi invio. Devi osservare quando avviene la stampa.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  5. #5
    Siamo d'accordo che se non do INVIO i dati non arrivano al programma.
    Quello che mi chiedo è come vengano gestiti gli escape (o newline nel caso specifico). Se il System.in.read() lo tolgo dal do/while interno (lasciando soltanto la verifica sull'esattezza del char), in console vedo - giustamente - la conseguenza di tre byte non verificati dal while, cioè mi scrive tre volte
    codice:
    Premi un tasto seguito da INVIO:
    I byte vengono letti uno per volta, qua ci sono, ma se inizia col verificare il char (la prima 'p' del tuo "pippo"), come fa a restare nel do/while interno per "neutralizzare" le newline?
    Non riesco a spiegarmi meglio.

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da Gas75 Visualizza il messaggio
    come fa a restare nel do/while interno per "neutralizzare" le newline?
    Il ciclo

    codice:
    do { 
        ch = (char) System.in.read();
    } while(ch == '\n' | ch == '\r');

    tradotto a parole significa: ripeti l'input se il carattere è '\n' (Line-Feed) oppure '\r' (Carriage-Return).
    Il risultato finale è una logica di input che "scarta" CR/LF, ovvero dopo la fine del while sei sicuro che ch NON è né il CR né il LF ma appunto un altro carattere.

    E' come se questo do-while fosse una ipotetica (!) funzione read_ignora_cr_lf() . Se riscrivessi il tutto come:

    codice:
    do { 
        System.out.print("Premi un tasto seguito da INVIO: "); 
        ch = read_ignora_cr_lf();
    } while(ch != 'q');

    ti "quadra" di più?
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  7. #7
    La tua spiegazione non fa una grinza . Ma mi dici anche che i caratteri di escape vengono processati dopo la lettera immessa dall'utente, come dimostra il tuo codice Prova. Una volta che 'p' non soddisfa il while interno, passa al while esterno, oppure resta "parcheggiata" e il while confronta gli escape per escluderli dal while esterno?

  8. #8
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da Gas75 Visualizza il messaggio
    Una volta che 'p' non soddisfa il while interno, passa al while esterno, oppure resta "parcheggiata" e il while confronta gli escape per escluderli dal while esterno?
    Input: p invio

    Flusso:

    Stampa "Premi ...."
    Lettura con read --> ch = 'p'
    ch non è né CR né LF, quindi il ciclo interno termina subito
    ch non è 'q' quindi il ciclo esterno si ripete
    Stampa "Premi ...."
    Lettura con read --> ch = '\r'
    ch è il CR, ripete
    Lettura con read --> ch = '\n'
    ch è il LF, ripete
    Lettura con read, QUI sta in attesa di altro input
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  9. #9
    Ok!! Quindi quando stampa "Premi..." deve ancora processare \r e \n! Il mio errore era credere che una volta passato da entrambi i while (per via di 'p'), stampando "Premi..." non tornasse nei do/while.

    Grazie mille! Preziosissimo come sempre!

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.