Mokabyte

Dal 1996, architetture, metodologie, sviluppo software

  • Argomenti
    • Programmazione & Linguaggi
      • Java
      • DataBase & elaborazione dei dati
      • Frameworks & Tools
      • Processi di sviluppo
    • Architetture dei sistemi
      • Sicurezza informatica
      • DevOps
    • Project Management
      • Organizzazione aziendale
      • HR
      • Soft skills
    • Lean/Agile
      • Scrum
      • Teoria della complessità
      • Apprendimento & Serious Gaming
    • Internet & Digital
      • Cultura & Società
      • Conferenze & Reportage
      • Marketing & eCommerce
    • Hardware & Tecnologia
      • Intelligenza artificiale
      • UX design & Grafica
  • Ultimo numero
  • Archivio
    • Archivio dal 2006 ad oggi
    • Il primo sito web – 1996-2005
  • Chi siamo
  • Ventennale
  • Libri
  • Contatti
  • Argomenti
    • Programmazione & Linguaggi
      • Java
      • DataBase & elaborazione dei dati
      • Frameworks & Tools
      • Processi di sviluppo
    • Architetture dei sistemi
      • Sicurezza informatica
      • DevOps
    • Project Management
      • Organizzazione aziendale
      • HR
      • Soft skills
    • Lean/Agile
      • Scrum
      • Teoria della complessità
      • Apprendimento & Serious Gaming
    • Internet & Digital
      • Cultura & Società
      • Conferenze & Reportage
      • Marketing & eCommerce
    • Hardware & Tecnologia
      • Intelligenza artificiale
      • UX design & Grafica
  • Ultimo numero
  • Archivio
    • Archivio dal 2006 ad oggi
    • Il primo sito web – 1996-2005
  • Chi siamo
  • Ventennale
  • Libri
  • Contatti

Nel numero:

115 febbraio
, anno 2007

Java e l‘encoding

In pratica

Avatar
Amedeo Cannone

Amedeo Cannone si è laureato in Ingegneria Informatica presso l‘università degli studi di Bologna.
Dal 2003 lavora per il Gruppo Imola per cui svolge attività di consulenza su tematiche architetturali e di processo.
Al momento sta seguendo alcuni progetti di integrazione SOA e si sta interessando di ESB e JBI.
Il profilo completo è visualizzabile su LinkedIn all‘indirizzo
http://www.linkedin.com/pub/dir/Amedeo/Cannone

MokaByte

Java e l‘encoding

In pratica

Picture of Amedeo Cannone

Amedeo Cannone

  • Questo articolo parla di: Java, Programmazione & Linguaggi

In questo articolo si affronta una delle problematiche tipiche delle applicazioni Java distribuite, ovvero quella legata all‘encoding delle stringhe. L‘argomento è sviluppato con un taglio pratico, senza parlare di internazionalizzazione, ma fornendo un quadro teorico per capire il comportamento di Java e una serie di indicazioni per prevenire e risolvere la visualizzazione di determinati caratteri con i soliti “???”.

 

Un po‘ di storia

L‘avvento della codifica ASCII permise di rappresentare tutte le lettere inglesi non accentate usando 7 bit. I computer di allora, che lavoravano a 8 bit, erano quindi in grado di memorizzare l‘insieme dei possibili caratteri ASCII e in più avevano a disposizione 1 bit che avanzava. Il problema fu che in molti decisero di sfruttare lo spazio di codici 128-255, relativo a questo ottavo bit.

Tra questi, IBM cominciò a usare per i suoi PC un set di caratteri, denominato OEM, che comprendeva alcune lettere accentate tipiche delle lingue europee, barre orizzontali e verticali etc…

Con la diffusione dei PC in tutto il mondo, i set di caratteri OEM proliferarono e si adattarono alle esigenze delle diverse lingue (p.e., il codice 130 corrispondeva al carattere europeo “è”, ma anche al carattere ebraico Gimel).

Per rimettere ordine, fu quindi coniato lo standard ANSI, che fissò le codifiche dei primi 128 caratteri, come aveva fatto l‘ASCII, e prese atto dei differenti sistemi di gestione dei rimanenti codici, quelli compresi tra 128 e 255, ai quali dette il nome di code page. Comparvero versioni di MS-DOS contenenti dozzine di code page per rispondere alle esigenze delle diverse lingue. Ben presto però non fu più sufficiente, sia perché i canonici 8 bit stavano comunque stretti ad alcuni alfabeti con migliaia di caratteri, sia perché, con la comparsa di Internet, si manifestò l‘esigenza di scambiare stringhe tra computer dislocati nelle diverse parti del mondo. Questi motivi portarono all‘invenzione dello lo standard di codifica Unicode.

 

Unicode

Unicode deriva quindi dal tentativo di creare un set di caratteri che vada bene per tutte le lingue conosciute. Unicode è un sistema di codifica a 16 bit, per un totale di 65536 possibili rappresentazioni, dette code point. La novità  è che, mentre fino ad allora ogni lettera era mappata in una sequenza di bit, in Unicode ad ogni carattere corrisponde un code point (p.e., U+0645), però non viene stabilito come rappresentarlo in memoria. Ed è qui che entra in gioco il concetto di encoding.

Oggi esistono molti sistemi di encoding, ma bisogna distinguere tra quelli tradizionali (CP-1252, ISO8859-1, etc.), che sono in grado di memorizzare solo alcuni code point in modo corretto e mappano i restanti nel carattere “?”, da quelli che possono invece memorizzare tutti i code point della codifica Unicode (UTF-7, UTF-8, UTF-16, etc.).

Tra questi ultimi sistemi di encoding, uno dei più usati è l‘UTF-8, che memorizza i vari code point con 8 bit alla volta (fino ad un massimo di 6 byte) e che per i code point 0-127 usa il primo byte. Quest‘ultima caratteristica fa sì che il normale testo inglese possa essere memorizzato allo stesso modo dei vari ASCII, ANSI, OEM e rende pertanto l‘UTF-8 compatibile con i precedenti sistemi di codifica a byte singolo (p.e., una vecchia stringa di testo in ASCII continua ad essere visualizzata correttamente in un sistema che usa la codifica UTF-8).

 

La rappresentazione dei caratteri in Java

Il linguaggio Java rappresenta i caratteri usando il sistema di codifica Unicode. Per questo motivo, ogni volta che in un‘architettura distribuita vengono scambiati dei dati testuali (per semplicità, si pensi a un file di testo) tra un sistema esterno e un‘applicazione Java avviene una conversione in Unicode.

Ora, tale conversione avviene in modo automatico e senza problemi se l‘encoding del testo corrisponde a quello di default della Java Virtual Machine (JVM). Ma se i due encoding differiscono, la conversione deve essere gestita in modo programmatico, pena la renderizzazione errata di alcuni caratteri con i soliti “?”. Questi errori di visualizzazione possono verificarsi, ad esempio, quando si fa una conversione da un file esterno con codifica UTF-8 a una applicazione Java su una piattaforma con encoding CP-1252 (si pensi a Windows che utilizza quest‘ultimo come encoding di default). Infatti il CP-1252, a differenza dell‘UTF-8, non è in grado di memorizzare tutti i code point del sistema Unicode ed è passibile di errori di trascodifica del file.

Vediamo a questo punto come si determina l‘encoding di default della JVM e quali API consentono la gestione della conversione del testo in Unicode. Per quanto riguarda l‘encoding della JVM, va detto che generalmente corrisponde all‘encoding di default della piattaforma sottostante. Comunque, a scanso di equivoci, per individuare l‘encoding di default usato è sufficiente creare un OutputStreamWriter e invocare il metodo getEncoding come mostrato nell‘esempio che segue:

OutputStreamWriter out = new OutputStreamWriter(new ByteArrayOutputStream());
System.out.println("encoding: " + out.getEncoding());

Parlando, invece, della gestione programmatica della conversione in Unicode, bisogna sottolineare che essa differisce a seconda che si usino gli stream di caratteri o gli stream di byte: nel primo caso (stream di caratteri), infatti, si deve creare un oggetto Charset corrispondente all‘encoding del file di testo e lo si deve passare al costruttore di InputStreamReader, mentre nel secondo caso (stream di byte) basta specificare l‘encoding nel costruttore della classe String.

Di seguito è riportato un frammento di codice d‘esempio che effettua la conversione di un file UTF-8 (TestoUTF-8.txt) in Unicode, usando sia gli stream di byte che di caratteri:

System.out.println("Reading strings");
try {
    Charset charset = Charset.forName("UTF-8");
 inString = new BufferedReader(new InputStreamReader(
 new FileInputStream(new File("TestoUTF-8.txt")), charset));
} catch (FileNotFoundException e) {
 e.printStackTrace();
}
try {
 String s;
 while ((s = inString.readLine()) != null){
 System.out.println(s);
 }
} catch (IOException e) {
 e.printStackTrace();
}
System.out.println("Reading bytes");
try {
 inByte = new FileInputStream(new File("TestoUTF-8.txt"));
} catch (FileNotFoundException e) {
 e.printStackTrace();
}
byte buffer[] = new byte[1000];
int n;
String b;
try {
 while((n= inByte.read(buffer)) > -1){
 b = new String(buffer,0,n,"UTF-8");
 System.out.print(b);
 }
} catch (IOException e) {
 e.printStackTrace();
}
try {
 inString.close();
 inByte.close();
} catch (IOException e) {
 e.printStackTrace();
}

Consigli pratici

Vediamo ora in concreto come bisogna comportarsi per evitare i problemi che si hanno in caso di applicazioni Java e sistemi esterni che si scambiano stringhe. Tali problemi, come detto, derivano da errori di trascodifica che si verificano quando si usano encoding differenti e che portano alla visualizzazione di caratteri “???”.

Innanzitutto dovrebbe essere ormai chiaro che quando si ha una stringa in un testo bisogna conoscere il suo encoding, altrimenti non si è sicuri di interpretarla e visualizzarla correttamente. Detto ciò, il modo più semplice per non avere problemi nel caso di un‘architettura distribuita da realizzare ex-novo è di scegliere una codifica di riferimento per i dati testuali e di usarla sia per i sistemi esterni che per le applicazioni Java. A tal proposito la codifica UTF-8, per le caratteristiche menzionate, si sta affermando come standard de facto.

Parlando, invece, di applicazioni già  implementate si può scegliere di intervenire a livello programmatico o cambiando l‘encoding di default sulle diverse piattaforme. Nel primo caso si opera a livello di API, come mostrato nel frammento di codice precedente, in modo da garantire la corretta trascodifica in Unicode. Questa soluzione non presenta controindicazioni, tuttavia non sempre è praticabile in quanto si può avere a che fare con delle API che non consentono di specificare l‘encoding. Si pensi ad esempio a una piattaforma con encoding di default ASCII su cui è presente un‘applicazione Java, che riceve un file di testo UTF-8 e logga con Log4J le stringhe lette. In questo caso, infatti, pur essendo presente la giusta trascodifica del file UTF-8, al momento di loggare le stringhe corrette che risiedono in memoria non si ha la possibilità  di specificare l‘encoding da usare; si ripiegherebbe quindi sull‘ASCII (l‘encoding di default della JVM), incorrendo nei noti problemi di visualizzazione di caratteri.

Per quanto riguarda il cambiamento dell‘encoding di default si hanno a disposizione le alternative seguenti, ciascuna con i suoi pro e contro.

La prima possibilità  consiste nel fissare a posteriori un encoding di default e di impostarlo sulle diverse piattaforme che ospitano i vari sistemi dell‘architettura distribuita in questione. Tale soluzione è la più drastica, in quanto l‘impostazione dell‘encoding a livello di sistema operativo si ripercuoterebbe anche sulle altre applicazioni presenti, con effetti da valutare caso per caso. Tale soluzione “drastica”, però, presenta il vantaggio di risolvere il problema anche per le future applicazioni distribuite che risiederanno sulle piattaforme interessate da tale modifica.

La seconda soluzione è meno invasiva, ma è limitata alle applicazioni Java. Per queste ultime è, infatti, possibile usare la proprietà  di sistema file.encoding per impostare un determintato encoding a livello di JVM, senza cambiare quello del sistema operativo sottostante. Per farlo, è sufficiente aggiungere l‘espressione

-Dfile.encoding= DefaultEncoding

nel lancio della JVM, impostando in questo modo il DefaultEncoding senza avere ripercussioni sulle altre applicazioni. In realtà , a essere precisi, si dovrebbero tenere in conto altre applicazioni Java contenute nella JVM interessata, ma in questi casi si possono eventualmente utilizzare delle JVM separate.

Va però sottolineato che, a livello ufficiale, Sun dichiara che la proprietà  di sistema file.encoding è read-only, e di conseguenza non è modificabile. Pertanto, sebbene cambiare le impostazioni di tale proprietà  funzioni in diversi casi, al momento si tratta di una pratica per la quale Sun non garantisce affidabilità  e supporto.

 

Conclusioni

Nel corso dell‘articolo si sono approfonditi il comportamento di Java nella rappresentazione di caratteri e i relativi problemi di trascodifica in un‘architettura distribuita in cui vengono scambiati dei dati testuali tra un sistema esterno e un‘applicazione Java. Per ovviare a questo tipo di problemi è sufficiente definire nelle nuove implementazioni lo stesso encoding per i dati testuali e per le applicazioni Java. Nel caso invece di applicazioni esistenti, sono state presentate due soluzioni: l‘una di tipo programmatico, l‘altra consistente nell‘impostazione dell‘encoding di default. La prima è quella preferibile poiché non ha controindicazioni, ma purtroppo non è sempre praticabile. L‘altra prevede due possibilità  (il setting dell‘encoding di default a livello di sistema operativo e il setting dell‘encoding con la proprietà  di sistema file.encoding), ciascuna con i suoi pro e i suoi contro.

 

Riferimenti

http://java.sun.com/docs/books/tutorial/i18n/text/convertintro.html

http://www.cs.tut.fi/~jkorpela/chars.html

http://www.joelonsoftware.com/articles/Unicode.html

http://ppewww.physics.gla.ac.uk/~flavell/iso8859/iso8859-pointers.html

 

 

Avatar
Amedeo Cannone

Amedeo Cannone si è laureato in Ingegneria Informatica presso l‘università degli studi di Bologna.
Dal 2003 lavora per il Gruppo Imola per cui svolge attività di consulenza su tematiche architetturali e di processo.
Al momento sta seguendo alcuni progetti di integrazione SOA e si sta interessando di ESB e JBI.
Il profilo completo è visualizzabile su LinkedIn all‘indirizzo
http://www.linkedin.com/pub/dir/Amedeo/Cannone

Facebook
Twitter
LinkedIn
Picture of Amedeo Cannone

Amedeo Cannone

Amedeo Cannone si è laureato in Ingegneria Informatica presso l‘università degli studi di Bologna. Dal 2003 lavora per il Gruppo Imola per cui svolge attività di consulenza su tematiche architetturali e di processo. Al momento sta seguendo alcuni progetti di integrazione SOA e si sta interessando di ESB e JBI. Il profilo completo è visualizzabile su LinkedIn all‘indirizzo http://www.linkedin.com/pub/dir/Amedeo/Cannone
Tutti gli articoli
Nello stesso numero
Loading...

Modalità di interazione con un sistema di versioning

Consigli pratici

Le applicazioni web e Java

La gestione della sessione

Ruby

II parte: approfondiamo alcuni aspetti del linguaggio Ruby

Location API

Una libreria Java ME per applicazioni georeferenziate

Spring

V parte: Web MVC

Teamwork in finale al Jolt Productivity Awards

Intervista a Pietro Polsinelli e Roberto Bicchierai di OpenLab

Maven: best practices applicate al processo di build e rilascio di progetti Java

II parte: l‘archetipo

Enterprise Java Beans 3.0

IV parte: approfondimenti sulla persistenza

Mokabyte

MokaByte è una rivista online nata nel 1996, dedicata alla comunità degli sviluppatori java.
La rivista tratta di vari argomenti, tra cui architetture enterprise e integrazione, metodologie di sviluppo lean/agile e aspetti sociali e culturali del web.

Imola Informatica

MokaByte è un marchio registrato da:
Imola Informatica S.P.A.
Via Selice 66/a 40026 Imola (BO)
C.F. e Iscriz. Registro imprese BO 03351570373
P.I. 00614381200
Cap. Soc. euro 100.000,00 i.v.

Privacy | Cookie Policy

Contatti

Contattaci tramite la nostra pagina contatti, oppure scrivendo a redazione@mokabyte.it

Seguici sui social

Facebook Linkedin Rss
Imola Informatica
Mokabyte