2010-03-28 19 views
5

Alcuni pseudocodice:codifica dei caratteri intesa in tipico Java web app

String a = "A bunch of text"; //UTF-16 
saveTextInDb(a); //Write to Oracle VARCHAR(15) column 
String b = readTextFromDb(); //UTF-16 
out.write(b); //Write to http response 

Quando si salva il Java String (UTF-16) per Oracle VARCHAR (15) fa Oracle ha anche memorizzare questo come UTF-16? La lunghezza di un VARCHAR Oracle si riferisce al numero di caratteri Unicode (e non al numero di byte)?

Quando scriviamo b su ServletResponse questo viene scritto come UTF-16 o convertiamo automaticamente in un'altra codifica come UTF-8?

risposta

4

Invece di UTF-16, si pensi alla "rappresentazione interna" della stringa. Una stringa in Java è una sorta di caratteri, non ti interessa quale codifica venga usata internamente. La codifica diventa rilevante se interagisci con l'esterno del programma. Nell'esempio saveTextInDb, leggiTextFromDb e scrivi fallo. Ogni volta che si scambiano stringhe con l'esterno, viene utilizzata una codifica per la conversione. saveTextInDb (e leggi) assomigliano ai metodi fatti da te, almeno non li conosco. Quindi dovresti cercare, quale codifica è usata per questi metodi. La scrittura del metodo di un writer crea sempre byte, che rappresentano una codifica associata allo scrittore. Se si ottiene il Writer da HttpServletResponse, la codifica associata è quella utilizzata per l'output della risposta (che verrà inviata nelle intestazioni).

Questo codice restituisce senza Writer, che converte le stringhe in codifica UTF-8. Simile se si scrive in un file:

Writer fileout = new OutputStreamWriter(new FileOutputStream(myfile), "ISO8859-1"); 

Se si accede a un DB, il quadro si utilizza dovrebbe garantire un costante scambio di stringhe con il database.

3

Il ServletResponse utilizzerà ISO 8859-1 (Latin 1) per impostazione predefinita. UTF-8 è la codifica più comune utilizzata per le risposte HTTP che richiedono Unicode, ma è necessario impostare specificatamente tale codifica.

Secondo this document Oracle può supportare UTF-8 o UTF-16 nel database. I tuoi metodi di lettura/scrittura di Oracle dovranno utilizzare la codifica appropriata che corrisponde a come è impostato il database e tradurlo in/dalla rappresentazione interna di Java.

4

La capacità di Oracle di archiviare (e successivamente recuperare) il testo Unicode dal database si basa solo sul set di caratteri del database (in genere specificato durante la creazione del database). La scelta di AL32UTF8 come set di caratteri è consigliata per l'archiviazione del testo Unicode nei tipi di dati CHAR (incluso VARCHAR/VARCHAR2), poiché consente di accedere a tutti i codepoint Unicode senza consumare molto spazio di archiviazione rispetto ad altre codifiche come AL16UTF16/AL32UTF32.

Supponendo che ciò avvenga, è il driver JDBC Oracle responsabile della conversione dei dati codificati UTF-16 in AL32UTF8. Questa conversione "automatica" tra le codifiche avviene anche quando i dati vengono letti dal database. Per rispondere alla query sulla lunghezza in byte di VARCHAR, la definizione di una colonna VARCHAR2 in Oracle implica semantica dei byte - VARCHAR2 (n) viene utilizzato per definire una colonna che può contenere n byte (questo è il comportamento predefinito, come specificato dal parametro NLS_LENGTH_SEMANTICS del database); se è necessario definire la dimensione in base ai caratteri VARCHAR2 (n CHAR) deve essere utilizzato.

La codifica dei dati scritti sull'oggetto ServletResponse dipende dalla codifica dei caratteri predefinita, a meno che non venga specificato tramite le chiamate API ServletResponse.setCharacterEncoding() o .Nel complesso, una soluzione completa Unicode coinvolge un database Oracle, si deve avere conoscenza di

  1. La codifica dei dati in arrivo (cioè la codifica dei dati letti tramite l'oggetto ServletRequest). Questo può essere fatto specificando la codifica accettata nei moduli HTML tramite accept-charset attribute. Se la codifica è sconosciuta, l'applicazione potrebbe tentare di impostarla su un valore noto tramite il metodo ServletRequest.setCharacterEncoding(). Questo metodo non modifica la codifica esistente dei caratteri nello stream. Se il flusso di input è in ISO-Latin1, specificare una codifica diversa causerà molto probabilmente un'eccezione. Conoscere la codifica è importante, poiché le librerie di runtime Java richiedono la conoscenza della codifica originale del flusso, se i contenuti del flusso devono essere trattati come primitive di caratteri o stringhe. Apparentemente, questo è richiesto quando invochi ServletRequest.getParameter o metodi simili che elaboreranno lo stream e restituiranno oggetti String. Il processo di decodifica comporterà la creazione di caratteri nella codifica della piattaforma (questo è UTF-16).
  2. La codifica dei dati letti dai flussi, al contrario dei dati creati con nella JVM. Questo è abbastanza importante, dal momento che la codifica dei dati letti dai flussi non può essere modificata. Esiste tuttavia un processo di decodifica che converte i caratteri nelle codifiche supportate in caratteri UTF-16, ogni volta che si accede a tali dati come carattere primitivo o come stringa. I nuovi oggetti String, d'altra parte, possono essere creati con una codifica definita. Questo è importante quando scrivi il contenuto dello stream su un altro stream (il flusso di output dell'oggetto HttpServletResponse per esempio). Se il contenuto del flusso di input viene trattato come una sequenza di byte e non come caratteri o stringhe, la JVM non intraprenderà alcuna operazione di decodifica. Ciò implicherebbe che i byte scritti nel flusso di output non debbano essere modificati se non vengono creati caratteri intermedi o oggetti String. Altrimenti, è del tutto possibile che il contenuto del flusso di output sia malformato e analizzato in modo errato da un decodificatore corrispondente. In parole più semplici,

    • se si scrive oggetti String o personaggi al flusso di output del servlet, allora si deve specificare la codifica che il browser deve utilizzare per decodificare la risposta. Gli encoder appropriati possono essere usati per codificare la sequenza di caratteri come specificato nella risposta desiderata.
    • se si sta scrivendo una sequenza di byte che verrà interpretata come caratteri, la codifica da specificare nell'intestazione HTTP deve essere nota prima della mano
    • se si sta scrivendo una sequenza di byte che verrà analizzata come sequenza di byte (per immagini e altri dati binari), quindi il concetto di codifica è irrilevante.
  3. Il set di caratteri database dell'istanza Oracle. Come indicato in precedenza, i dati verranno archiviati nel database Oracle, nel set di caratteri definito (per i tipi di dati CHAR). Il driver JDBC Oracle si occupa della conversione dei dati tra UTF-16 e AL32UTF8 (il set di caratteri del database in questo caso) per i tipi di dati CHAR e NCHAR. Quando invochi resultSet.getString(), viene restituita una stringa con caratteri UTF-16 dal driver JDBC. Il contrario è vero, quando si inviano anche dati al database. Se viene utilizzato un altro set di caratteri del database, un ulteriore livello di conversione (da UTF-16 a UTF-8 al set di caratteri del database) viene eseguito in modo trasparente dal driver JDBC.
Problemi correlati