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
Menu
  • 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
Cerca
Chiudi

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

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

Facebook
Twitter
LinkedIn
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

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...

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

Modalità di interazione con un sistema di versioning

Consigli pratici

Nella stessa serie
Loading...

Un sistema di monitoraggio del traffico veicolare “in tempo reale”

VI parte: Data processing e persistenza

WebAssembly, uno standard web per il presente e per il futuro

I parte: Panoramica e caratteristiche

Cos’è che fa di un DevOps un DevOps?

Principi, pratiche, ruolo

Quindici statistiche da conoscere per lavorare in UX design

Uno sguardo internazionale

Un sistema di monitoraggio del traffico veicolare “in tempo reale”

V parte: Data Ingestion & Computing

User Story Game

Capire l’importanza delle User Stories… giocando

Sbagliando si impara?

Elenco ragionato di alcuni errori tipici nella pratica Scrum

Cybersecurity e cloud computing

Le basi per mettere in sicurezza il cloud

Un sistema di monitoraggio del traffico veicolare “in tempo reale”

IV parte: L’invio dei dati al topic di Kafka

Verso #play14 Bologna 2022

Cosa era successo la volta precedente

Product Owner: chi è?

Perché non è un Project Manager agile?

Come monitorare l’avanzamento dei lavori in Agile

Misurare lo stato di avanzamento di un progetto in Agile

Contributors

Un sistema di monitoraggio del traffico veicolare “in tempo reale”

III parte: Il framework Spark

Kanban in pratica

Qualche suggerimento in azione

Comunicazione tra microservizi con Apache Kafka

Un esempio pratico

OKR, cadenze in Kanban e Flight Levels

Uscire dalla trappola dell’agilità locale

Un sistema di monitoraggio del traffico veicolare “in tempo reale”

II parte: Tecnologie di analisi

Big Data vs Fast Data

Estrarre valore dai dati in tempo reale

Lean Manufacturing e Agile

Esempi applicativi di integrazione possibile

Approccio Agile e pianificazione strategica

La coesistenza è possibile?

Impact Mapping e Liminal Thinking

II parte: Progettare gli impatti

Un sistema di monitoraggio del traffico veicolare “in tempo reale”

I parte: Introduzione e panoramica

Agile Coaching

Un modello operativo per l'agile coach

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