DUBBIO su InputStreamReader

di il
6 risposte

DUBBIO su InputStreamReader

Seguendo gli appunti del corso java base seguito , mi si dice che:
<<se INCAPSULIAMO System.in nello InputStreamReader ,
allora lo stream: InputStreamReader "ci permette di LEGGERE direttamente CARATTERI e NON più byte">>
Tuttavia ,facendo delle prove, ho notato che:
o mi invoco il metodo:read() della Classe:InputStream sullo stream: System.in
o mi invoco il metodo:read() della Classe:InputStreamReader -una volta che le abbiamo fatto incapsulare System.in-

--> quel metodo mi restituisce sempre ""la rappresentazione come intero del byte LETTO""

Domanda: perché ,per LEGGERE 1CARATTERE da Tastiera , si è soliti incapsulare System.in ?

Versione senza incapsulamento
import java.io.*;
public class prova{
	public static void main(String[] args){
	
	System.out.println("digita un tasto: ");
	try{
	   int x=System.in.read();
	  char ch=(char) x;
	System.out.println("Carattere digitato: "+ch);				 
	}
	catch(Exception ex){
	 System.out.println("Errore Lettura");
	 System.exit(2);
	}

 }//end main
}//end class
Versione con incapsulamento
import java.io.*;
public class prova{
	public static void main(String[] args){
	InputStreamReader tastiera =new InputStreamReader(System.in);
	//[LETTURA] da Tastiera
	System.out.println("digita un tasto: ");
	try{
	   int x=tastiera.read();
	   char ch=(char) x;
	System.out.println("Carattere digitato: "+ch);				 
	}
	catch(Exception ex){
	 System.out.println("Errore Lettura");
	 System.exit(2);
	}

 }//end main
}//end class

6 Risposte

  • Re: DUBBIO su InputStreamReader

    pepp1995 ha scritto:


    <<se INCAPSULIAMO System.in nello InputStreamReader ,
    allora lo stream: InputStreamReader "ci permette di LEGGERE direttamente CARATTERI e NON più byte">>
    Sì è il concetto corretto.

    pepp1995 ha scritto:


    --> quel metodo mi restituisce sempre ""la rappresentazione come intero del byte LETTO""
    C'è una questione ... il "charset". System.in è un InpuStream, che NON ha alcuna nozione del charset, legge solo byte e basta.
    InputStreamReader invece ha anche la nozione del charset (implicito o esplicitato alla costruzione). E ovviamente dipende anche dal charset della piattaforma.
    Se operassi sui sistemi Linux, tipicamente il charset predefinito della piattaforma è UTF-8. In questo caso se inserisci "è" (e accento grave) in UTF-8 sono 2 byte, quindi servono 2 System.in.read() per leggere quei due byte. Ma NON sono caratteri!
    Se invece incapsuli il System.in in InputStreamReader (usando il charset implicito), con esso basta fare isr.read() per leggere il char che è codificato da quei 2 byte.
    La questione è tutta lì ...
  • Re: DUBBIO su InputStreamReader

    quindi servono 2 System.in.read() per leggere quei due byte
    OK, fin qui ci sono.
    basta fare isr.read() per leggere il char che è codificato da quei 2 byte
    Quindi il metodo: read() della Classe:InputStreamReader
    A)[LEGGE]sempre ""2byte alla volta"" dallo stream ?
    B) oppure ,in un certo senso,"si adatta alla codificaDelCarattere adottata dalla piattaforma " e dunque ad ogni invocazione [LEGGE] numero byte pari a "quanti ce ne vogliono affinché quegli n-byte letti siano un carattere" ?
  • Re: DUBBIO su InputStreamReader

    pepp1995 ha scritto:


    A)[LEGGE]sempre ""2byte alla volta"" dallo stream ?
    No, DIPENDE dal charset. Ne esistono a decine e il framework di Java ha tutti gli encoder/decoder per supportarli tutti o quasi (nel JDK8 il availableCharsets() di java.nio.charset.Charset fornisce una mappa di 170 charset).
  • Re: DUBBIO su InputStreamReader

    Scusa ma non mi sembra ancora chiaro
    In questo caso se inserisci "è"
    basta fare isr.read() per leggere il char che è codificato da quei 2 byte.
    Il Problema è che: da windows , sia utilizzando il metodo:read() dello stream System.in sia utilizzando lo stesso metodo ma nel caso dello stream incapsulato --> mi stampa '?'
    Nel 1° caso , non mi ha stampato la 'è' (con accento) perché ha letto solo 1byte
    Ma nel 2° caso, visto che sto utilizzando l' InputStreamReader -->non dovrebbe permettermi di Leggere la 'è' ?
  • Re: DUBBIO su InputStreamReader

    pepp1995 ha scritto:


    Il Problema è che: da windows , sia utilizzando il metodo:read() dello stream System.in sia utilizzando lo stesso metodo ma nel caso dello stream incapsulato --> mi stampa '?'
    Nel 1° caso , non mi ha stampato la 'è' (con accento) perché ha letto solo 1byte
    Ma nel 2° caso, visto che sto utilizzando l' InputStreamReader -->non dovrebbe permettermi di Leggere la 'è' ?
    No no. Allora: innanzitutto sui "vecchi" Windows (parlo perlomeno fino al Win 7) il charset della piattaforma era sempre il Windows-1252 (perlomeno sui pc "italiani"). Il Windows-1252 è un charset single-byte (sempre e solo 1 byte x carattere), quindi comunque parecchio limitato.

    Su Windows 10 ho notato invece una cosa:

    System.out.println(Charset.defaultCharset());

    stampa UTF-8 se lo avvio da Eclipse mentre stampa windows-1252 se lo avvio da Prompt comandi.

    Su Eclipse funziona tutto correttamente quindi, sulla console di Eclipse una "è" inserita genera 2 byte, il InputStreamReader (con default charset) legge i due byte e fornisce un char codice 232 che è il codice Unicode corretto per la "è".

    Da Prompt comandi (windows-1252) inserendo una "è" viene generato solo un byte codice 138 che però NON è relativo al Windows-1252.
    Sui Windows c'è un'altra grana. La console ha un suo "code page" (concetto vecchio ... già dal DOS). Se da prompt lanci il comando "mode", ottieni es.:
    Stato del dispositivo CON:
    --------------------------
        Linee:                500
        Colonne:              100
        Velocità ripetizione: 31
        Ritardo:              1
        Tabella codici:       850
    Quel 850 è il code page 850 (cp850) e in questo set di caratteri effettivamente la "è" ha codice 138. Il problema è che Java lo legge "sapendo" del Windows-1252 quindi "mappa" il carattere sbagliato. Il problema NON è Java, il problema è il set di caratteri della CONSOLE che differisce da quello di default che Java "vede".

    Quindi: "è" da Prompt genera il codice 138 (cp850), Java lo interpreta nel Windows-1252, dove 138 è il carattere "Š" che è il codice Unicode U+0160 (352 in decimale). Se però stampi questo "Š" di nuovo su console .... nel cp850 NON esiste, non è mappato, quindi ottieni un bel "?".

    Questa purtroppo è una grana dei Windows. L'unico modo buono per risolverla è usare la classe java.io.Console che esiste da Java 6 e ha maggiore nozione appunto della console (anche e soprattutto su Windows).

    Spero che la spiegazione non ti abbia confuso ma con i charset bisogna prestare ATTENZIONE perché bisogna vedere da dove si parte, dove si arriva (es. stampando dove), quale/i charset sono coinvolti e a quale livello, ecc...
  • Re: DUBBIO su InputStreamReader

    Premessa1: grazie per la pazienza

    Premessa2: ho fatto dei test su una distro live linux ed effettivamente ho notato che : digitando una 'è'
    Risultato: 1. con la versione NON incapsulata -->mi viene stampato un carattere NON corretto , nello specifico una 'A' (col tilde)
    risultato che mi aspettavo perché ho LETTO solo il 1°byte dei 2 che mi sarebbero serviti per rappresentare effettivamente il carattere
    2. con la versione incapsulata --> effettivamente mi viene stampato il carattere corretto 'è',
    perché <<internamente,mi verrà automaticamente chiamato il metodo() per la lettura di 1byte
    ""il numero di volte che mi serve affinché quel carattere sia effettivamente letto "">>

    Da stackoverflow ho letto che:
    -in generale: quando pigiamo un tasto sulla tastiera , viene inviato un codice che sostanzialmente comunica quel è il tasto pigiato come se fosse "un elemento di una matrice" . Cosa riceve l'Applicazione invece dipende dalla convenzione adottata dal Sistema Operativo , nello specifico:
    -in Windows: dipende da come i CARATTERI sono codificati dal "code page" della console (che possiamo visualizzare dando il comando: chcp , nel mio caso 850)
    -in Linux: le Applicazioni solitamente utilizzano la codifica UTF-8

     A console application on Windows with chcp 1250 will get one byte '\xE3' (227 decimal).
        A console application on Windows with chcp 852 will get one byte '\xC7' (199 decimal).
        A graphical application on Windows will get a suitable key symbol, which usually will get stored/processed as two bytes '\x03' '\x01' (or as the short integer 0x103).
        A terminal application on Linux will get two bytes '\xC4' '\x83' (<U+0103> in UTF-8 encoding).
        A graphical application on Linux will get a suitable key symbol, which usually will get stored/processed as two bytes '\xC4' '\x83' (<U+0103> in UTF-8 encoding).
    Windows-1252 è un charset single-byte (sempre e solo 1 byte x carattere)
    Da Prompt comandi (windows-1252) inserendo una "è" viene generato solo un byte codice 138 che però NON è relativo al Windows-1252.
    Ma è relativo al "code page" del prompt di comandi.
    Il problema è che Java lo legge "sapendo" del Windows-1252 quindi "mappa" il carattere sbagliato
    Nello specifico: 1.la pressione di 'è' da Prompt --> genera il codice 138 in base al Code Page(a questo set di caratteri "proprio" del prompt di comandi),
    2.dopodiché, java va a cercare il carattere corrispondente a quel codice 138 in quello che "lui" si aspetta sia il set di caratteri Windows ovvero il windows-1252 --> e dunque lì trova il carattere"Š"
    3. al momento della stampa (a video) , però il carattere dev'essere visualizzato "sul prompt" , dunque dobbiamo far di nuovo riferimento al Charset dettato dal Code Page --> tuttavia lì quel carattere non esiste e dunque mi stampa un '?'
    Spero che la spiegazione non ti abbia confuso .
    Sei stato cristallino!

    Questa purtroppo è una grana dei Windows. L'unico modo buono per risolverla è usare la classe java.io.Console che esiste da Java 6 e ha maggiore nozione appunto della console (anche e soprattutto su Windows).
    Credo che per evitare di avere dubbi dettati "esclusivamente" da Windows e non dalla teoria del linguaggio , mi converrà fare test anche su Linux.
Devi accedere o registrarti per scrivere nel forum
6 risposte