1. Il concetto di codifica (encoding)
Cominciamo dalla domanda principale: che cos'è una codifica?
Immaginate di essere a una conferenza internazionale. Ognuno parla la propria lingua, ma tutti vogliono capirsi. Serve un traduttore che sappia che "hello" in inglese corrisponde a "privet" in russo e a "hola" in spagnolo. Nel mondo dei computer la codifica è proprio quel traduttore.
La codifica è un modo di rappresentare i caratteri sotto forma di byte
Il computer è semplice: capisce solo zeri e uno, cioè bit e byte. Le persone invece vogliono vedere lettere, cifre, emoji e perfino — oh, orrore! — ideogrammi cinesi. Per permettere al computer di «scrivere» un carattere, bisogna accordarsi su quale sequenza di byte corrisponde a ciascun carattere.
Una codifica (encoding) è un insieme di regole secondo cui i caratteri (lettere, cifre, segni di punteggiatura, emoji, ecc.) vengono trasformati in byte per l'archiviazione e la trasmissione, e viceversa: i byte vengono trasformati in caratteri per la visualizzazione.
Esempio: la lettera 'A' in diverse codifiche
- Nella codifica UTF-8 la lettera 'A' (cirillica) è codificata con due byte: 0xD0 0x90.
- Nella codifica Windows-1251 la stessa lettera — un solo byte: 0xC0.
- La 'A' latina, invece, in quasi tutte le codifiche diffuse è 0x41.
Se si legge un file con la codifica sbagliata, i caratteri si trasformano in «mojibake» (simboli incomprensibili o punti interrogativi).
2. Perché servono le codifiche
Perché non possiamo semplicemente memorizzare le lettere così come sono?
Perché il computer capisce solo numeri (zeri e uno). A quale numero corrisponde quale lettera — questa è l'essenza della codifica.
Esempio: «Privet» su disco
Quando scrivete in un file la parola "Privet", per il computer è solo una sequenza di byte. Come interpretare questi byte dipende dalla codifica.
- Se il file è scritto in UTF-8, ogni lettera cirillica occupa due byte, e così via.
- Se è in Windows-1251, ogni lettera occupa un byte, ma i valori dei byte sono diversi.
Dove servono le codifiche?
- Durante la scrittura di testo su file: affinché i byte possano poi essere letti correttamente.
- Durante la lettura di testo da file: perché i byte tornino a essere lettere.
- Nell'invio di testo in rete (per esempio, HTTP, e‑mail).
- Nella gestione dei database: anche lì bisogna sapere in quale codifica è memorizzato il testo.
Se non si specifica la codifica...
È come aprire un testo in una lingua sconosciuta e provare a leggerlo. Le probabilità aumentano se sapete di quale lingua si tratta. Se non lo sapete, nel migliore dei casi non capirete nulla, nel peggiore — otterrete pura abracadabra.
3. Problemi senza una codifica corretta
«Mojibake» e perdita di dati
La lamentela più comune dei programmatori principianti (e non solo): «Perché invece di "Privet" vedo "Привет" o addirittura solo punti interrogativi?»
Succede quando il file è stato scritto con una codifica, ma viene letto con un'altra. Per esempio, il file è stato creato su un vecchio Windows in Windows-1251, e lo aprite in Linux, dove la codifica predefinita è UTF-8. O viceversa.
Esempio
- File scritto in Windows-1251: il byte per la lettera iniziale (cirillica) è 0xCF.
- Il file viene aperto in UTF-8: il programma si aspetta che il cirillico occupi due byte, ma riceve un solo byte. Tutto si rompe.
Perdita di dati
Se in scrittura un carattere non è supportato dalla codifica scelta (per esempio, si tenta di salvare un'emoji in ASCII), scomparirà o verrà sostituito da un punto interrogativo. Tutto ciò che non «entra» nella codifica va perso.
Problemi nello scambio di file
File scritti in una codifica possono essere visualizzati in modo errato su altri computer, se lì è impostata una codifica predefinita diversa. Succede spesso nello scambio di file tra Windows e Linux o nell'apertura di file datati.
4. Codifica in Java: rappresentazione interna ed esterna
All'interno della JVM: sempre Unicode (UTF-16)
In Java le stringhe (String) all'interno del programma sono sempre memorizzate in Unicode (più precisamente in UTF-16). Significa che potete assegnare alle variabili stringhe in qualsiasi lingua del mondo e Java «digerirà» tutto.
String hello = "Ciao, mondo! 😀";
In memoria JVM questo testo è memorizzato come insieme di numeri a 16 bit (char), dove a ogni carattere corrisponde il suo codice nella tabella Unicode.
Curiosità
In Java un char è di 16 bit (2 byte). Ma alcuni caratteri (per esempio ideogrammi rari o emoji) richiedono due char — sono le «coppie surrogate».
I/O: la codifica conta!
Quando leggete o scrivete stringhe verso l'esterno (file, rete), Java deve convertire la rappresentazione interna (UTF-16) in una sequenza di byte. È qui che serve la codifica.
- Se non specificate esplicitamente la codifica, Java usa quella di sistema predefinita (su Windows in russo può essere Windows-1251, su Linux — UTF-8).
- È rischioso: su un altro computer il risultato può essere diverso.
Esempio: lettura e scrittura di file senza specificare la codifica
// Pratica sbagliata! Nessuna codifica specificata.
FileReader reader = new FileReader("data.txt");
FileWriter writer = new FileWriter("data.txt");
In tal caso Java usa la codifica di sistema. Se il file è stato scritto su un altro sistema — otterrete «mojibake».
Buona pratica: specificare sempre la codifica
// Bene! La codifica è specificata esplicitamente.
BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream("data.txt"), StandardCharsets.UTF_8));
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream("data.txt"), StandardCharsets.UTF_8));
5. Illustrazione breve: cosa succede quando si lavora con le codifiche
Schema: il percorso di una stringa dal file al programma e ritorno
[File su disco (byte, codifica X)]
|
V
[Java legge i byte e con la codifica X li trasforma in String (UTF-16)]
|
V
[Si lavora con la stringa nel programma]
|
V
[Java scrive la String in byte usando la codifica Y]
|
V
[File su disco (byte, codifica Y)]
Se X e Y coincidono — tutto bene. Se sono diversi — possono sorgere problemi.
6. Breve storia delle codifiche (per i curiosi)
ASCII
ASCII è una delle codifiche più antiche: un byte per carattere, solo alfabeto inglese, cifre e segni di base. Qualsiasi altro alfabeto — escluso.
Windows-1251, ISO-8859-1 e altri «vecchietti»
Sono codifiche a un byte per set di lettere differenti: cirillico, latino, greco, ecc. Ognuno ne sceglieva una propria e regnava la confusione.
Unicode e famiglia UTF
- Unicode — la tabella globale per i caratteri del mondo.
- UTF-8, UTF-16, UTF-32 — modi diversi di rappresentare i caratteri Unicode in byte.
- UTF-8 è diventato lo standard per il Web, i file e lo scambio tra sistemi.
7. Pratica: come la codifica influisce sul lavoro con i file
Vediamo un piccolo esempio di scrittura e lettura di stringhe con codifiche diverse.
Esempio: scrittura e lettura con codifiche diverse
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class EncodingDemo {
public static void main(String[] args) throws IOException {
String text = "Ciao, mondo! 😀";
// Scriviamo il file in UTF-8
try (Writer writer = new OutputStreamWriter(
new FileOutputStream("utf8.txt"), StandardCharsets.UTF_8)) {
writer.write(text);
}
// Ora proviamo a leggerlo con la codifica sbagliata
try (Reader reader = new InputStreamReader(
new FileInputStream("utf8.txt"), Charset.forName("Windows-1251"))) {
int c;
while ((c = reader.read()) != -1) {
System.out.print((char) c);
}
}
// Sullo schermo apparirà testo illeggibile!
}
}
Conclusione: Se le codifiche non coincidono — il testo verrà alterato.
8. Codifica e integrazione con altri sistemi
Nei progetti reali i file vengono spesso scambiati tra programmi diversi, scritti in linguaggi differenti e in esecuzione su sistemi operativi diversi. Ognuno può aspettarsi una propria codifica. Se non ci si accorda in anticipo — avrete «mojibake» e bug difficili da individuare. Caso tipico: il database memorizza il testo in UTF-8, ma il programma legge il file sorgente come Windows-1251 e lo carica nel DB — i caratteri verranno alterati.
9. Errori tipici nel lavoro con le codifiche
Errore n. 1: nessuna codifica specificata in lettura/scrittura del file.
Di conseguenza il programma funziona «sul mio computer», ma sul PC del collega compaiono «mojibake».
Errore n. 2: uso di costruttori obsoleti (FileReader, FileWriter).
Usano sempre la codifica di sistema — una trappola per i principianti.
Errore n. 3: codifica errata del file sorgente.
Se il file è stato scritto in una codifica e viene letto in un'altra, parte dei caratteri verrà alterata o sostituita da punti interrogativi.
Errore n. 4: perdita di caratteri nel passaggio tra codifiche.
Se la codifica di destinazione non supporta tutti i caratteri (per esempio, ASCII invece di UTF-8), parte del testo andrà semplicemente persa.
GO TO FULL VERSION