2010-02-04 5 views
16

Sto provando a passare un byte [] contenente caratteri ASCII a log4j, per essere registrato in un file usando la rappresentazione ovvia. Quando passo semplicemente in byt [], viene trattato come un oggetto e i registri sono piuttosto inutili. Quando provo a convertirli in stringhe usando new String(byte[] data), le prestazioni della mia applicazione sono dimezzate.Converti byte ASCII [] in stringa

Come posso passare in modo efficiente, senza incorrere nella penalità di circa 30 secondi di conversione in stringhe.

Inoltre, perché ci vuole così tanto tempo per convertirli?

Grazie.

Modifica

Vorrei aggiungere che io sono optmising per la latenza qui - e sì, 30US fa la differenza! Inoltre, questi array variano da ~ 100 fino a qualche migliaio di byte.

risposta

13

Che cosa si vuole fare è l'elaborazione di ritardo del byte [] array fino log4j decide che in realtà vuole registrare il messaggio. In questo modo è possibile registrarlo a livello di DEBUG, ad esempio, durante il test e poi disabilitarlo durante la produzione. Ad esempio, si potrebbe:

final byte[] myArray = ...; 
Logger.getLogger(MyClass.class).debug(new Object() { 
    @Override public String toString() { 
     return new String(myArray); 
    } 
}); 

Ora non pagate la pena di velocità a meno che effettivamente registrare i dati, perché il metodo toString non viene chiamato fino log4j decide che troveremo a registrare il messaggio!

Ora non sono sicuro di cosa intendiate per "rappresentazione ovvia", quindi ho assunto che intendiate convertire in una stringa reinterpretando i byte come codifica dei caratteri predefinita. Ora se hai a che fare con dati binari, questo è ovviamente senza valore. In quel caso io suggerirei usando Arrays.toString(byte[]) per creare una stringa formattata lungo le linee di

[54, 23, 65, ...] 
+2

Bello, utilizzando un logger asincrono sposta la conversione dal percorso critico. – jwoolard

16

ASCII è una delle poche codifiche che può essere convertito da/per UTF16 senza ricerche aritmetiche o da tavolo in modo che sia possibile convertire manualmente:

String convert(byte[] data) { 
    StringBuilder sb = new StringBuilder(data.length); 
    for (int i = 0; i < data.length; ++ i) { 
     if (data[i] < 0) throw new IllegalArgumentException(); 
     sb.append((char) data[i]); 
    } 
    return sb.toString(); 
} 

ma assicurarsi che in realtà è ASCII, o si finirà con la spazzatura.

+0

Grazie - questo l'ha ridotto di circa il 60% ... – jwoolard

+0

Questo codice funziona per me. Ma la nuova stringa (byteArray) ha causato il blocco della mia app Android. Puoi spiegare la differenza? –

8

Se i dati sono in realtà ASCII (cioè dati a 7 bit), allora si dovrebbe utilizzare new String(data, "US-ASCII") invece che in base alla codifica piattaforma predefinita. Questo potrebbe essere più veloce di cercare di interpretarlo come codifica predefinita della piattaforma (che potrebbe essere UTF-8, che richiede più introspezione).

È anche possibile velocizzare questo evitando il colpo di Charset-Lookup ogni volta, memorizzando nella cache l'istanza Charset e chiamando new String(data, charset) invece.

Detto questo: è stato un molto, molto tempo da quando ho visto i dati reali ASCII in ambiente di produzione

+0

qual è la differenza tra questa e la risposta di finnw? – Zyoo

+2

Dipende dal tipo di ambiente di produzione in cui ti trovi, signore. Lo vedo ogni giorno. – RW4

1

prestazioni dimezzato? Quanto è grande questo array di byte? Se è ad esempio 1 MB, ci sono sicuramente più fattori da prendere in considerazione rispetto alla semplice "conversione" da byte a caratteri (che dovrebbe essere abbastanza veloce).Scrittura 1 MB di dati anziché "solo" 100 byte (che il byte[].toString() può generare) in un file di registro ovviamente richiederà un po 'di tempo. Il file system del disco non è veloce come la memoria RAM.

È necessario modificare la rappresentazione della stringa dell'array di byte. Forse con alcune informazioni più sensibili, ad es. il nome associato ad esso (nomefile?), la sua lunghezza e così via. Dopotutto, cosa rappresenta quell'array di byte in realtà?

Edit: Non mi ricordo di aver visto il "circa 30US" frase nella sua interrogazione, forse si è modificato in entro 5 minuti dopo aver chiesto, ma questo è in realtà microoptimization e dovrebbe certamente non causa "prestazioni dimezzate" in generale. A meno che tu non li scriva un milione di volte al secondo (ancora allora, perché vorresti farlo? Non stai esagerando con il "logging" del fenomeno?).

+0

Questi array variano enormemente, da circa 150 byte fino a 4000 byte. ri. il tuo ultimo punto, sto ottimizzando la latenza piuttosto che il throughput - quindi devo spostare questa conversione dal percorso critico o accelerarla ... – jwoolard

+0

Inoltre, c'è un requisito per registrare tutti questi dati - e sì , è un sacco di dati ... – jwoolard

+0

Quindi il collo di bottiglia è più nell'IO del disco che nel codice Java - come mi aspettavo. – BalusC