Il modo migliore per utilizzare un InputStream per quanto riguarda persistenza e XML
-
10-07-2019 - |
Domanda
Ho un servizio web REST che ascolta le richieste POST e afferra un payload XML dal client e lo memorizza inizialmente come InputStream, cioè sull'oggetto Rappresentazione che puoi chiamare getStream () .
Voglio utilizzare l'XML contenuto in InputStream e sto cominciando a pensare che sarebbe saggio persisterlo, così posso interrogare i dati più volte - come una volta letto, l'oggetto diventa nullo. Quindi ho pensato di convertire InputStream in una stringa. Questa non è una buona idea in quanto DocumentBuilder.parse () dalla libreria javax.xml.parsers ti consentirà solo di passare:
- InputStreams
- File
- URL
- Fonti di input SAX
non stringhe.
Cosa dovrei davvero fare qui con InputStreams in relazione all'analisi di XML da esso? Tenendo presente che vorrò ri-interrogare quell'XML nei processi futuri con il codice.
Soluzione
Se si dispone di un InputStream e si desidera utilizzarlo come documento XML, perché non lo si sta semplicemente analizzando e passando l'oggetto Document? Se vuoi persistere su questo oggetto, usa un serializzatore per riscriverlo come testo.
Come ho notato nel mio commento a Tom Hawtin, la codifica è molto importante quando si ha a che fare con XML. Piuttosto che scrivere qui un lungo post che potrebbe non farti capire la tua situazione specifica, ecco un articolo che ho scritto.
Modifica: in realtà, dal momento che il mio articolo non parla specificamente di servizi Web, dovrei approfondire un po 'qui. Esistono due posizioni in cui è possibile specificare la codifica del contenuto: nel prologo XML o nell'intestazione della risposta Content-Type . Secondo le specifiche XML, la prima è quella che si desidera utilizzare ed è ciò che verrà utilizzato dal parser. Nella maggior parte dei casi, ciò non importa: un servizio web creato da una persona che non conosce la specifica utilizzerà in genere un testo / xml senza una specifica del set di caratteri (che è errata ma probabilmente non causerà danni). Se fanno le cose correttamente, specificheranno application / xml, con codifica utf-8. Tuttavia, dovresti verificare ciò che stai ricevendo, in modo da non finire con una strana codifica che il parser non è in grado di gestire.
Altri suggerimenti
Vorrei consigliare di utilizzare la libreria Apache Commons IO . La classe IOUtils contiene molti metodi utili per converte InputStreams in String e viceversa.
Generalmente, quando parliamo di persistenza, stiamo parlando di scriverlo su disco o altri media. C'è un impatto sulle prestazioni lì e devi pensare alle preoccupazioni relative allo spazio su disco. Ti consigliamo di metterlo a confronto con il valore di avere quell'XML a lungo termine.
Se stai solo parlando di tenerlo in memoria (che suona come quello che stai chiedendo), allora potresti allocare un array di byte e leggere tutto nell'array di byte. Puoi usare ByteArrayInputStream per leggere e rileggere quel flusso.
Il costo è duplice. Innanzitutto, ne stai conservando una copia in memoria e devi valutarla rispetto ai tuoi requisiti di scalabilità. In secondo luogo, analizzare XML è alquanto costoso, quindi è meglio analizzarlo una sola volta, se possibile, e salvare il risultato in un oggetto.
Modifica:
Per allocare e leggere l'array di byte, puoi spesso (ma non sempre) fare affidamento sul metodo disponibile () di InputStream per dirti quanto allocare. e avvolgi InputStream con un DataInputStream in modo da poter chiamare readFully () per aspirare il tutto nell'array di byte con una chiamata.
Modifica di nuovo:
Leggi il commento di Steen di seguito. Ha ragione nel dire che è una cattiva idea usare available () in questo caso.
Se si desidera utilizzare più volte l'XML, perché non analizzarlo una volta da InputStream (che è un lavoro pesante), e quindi conservare il documento restituito?
Penso che dovresti esaminare alcune strutture più adatte alla conservazione delle codifiche (ad es. più codifica agnostica). Per le strutture di basso livello, considera byte []
(ma fai attenzione con la deallocazione della memoria!) Oppure potresti provare a progettare un tipo di dati adatto alle tue esigenze.
Puoi leggere InputStream
in un ByteArrayOutputStream
(utilizzando uno dei read ()
metodi) ed estrai il byte []
da lì .
java.io.StringReader
ti permetterà di usare InputSource
.
Potresti voler archiviare i dati in un byte []
e quindi leggere con ByteArrayInputStream
. Se è particolarmente grande, potresti prendere in considerazione la compressione. Questo può essere letto con GzipInputStream
, che spesso dovrebbe essere racchiuso in un BufferedInputStream
.