Giustificazione per la progettazione dell'interfaccia pubblica di ByteArrayOutputStream?

StackOverflow https://stackoverflow.com/questions/6325596

  •  27-10-2019
  •  | 
  •  

Domanda

Ci sono molte librerie Java standard e 3 ° parti che nella loro API pubblica, ci sono metodi per la scrittura o la lettura da Stream. Un esempio è javax.imageio.ImageIO.write() che prende OutputStream scrivere il contenuto di un'immagine elaborata ad esso. Un altro esempio è iText libreria pdf elaborazione che prende OutputStream di scrivere il PDF risultante ad esso. Terzo esempio è AmazonS3 API Java, che prende InputStream in modo che leggerà e creare file in thir accumulo S3 .

Il problema araises quando si desidera combinare due di questi. Ad esempio, ho un'immagine come BufferedImage per cui devo usare ImageIO.write per spingere il risultato in OutputStream. Ma non c'è nessuna diretta modo per spingerlo ad Amazon S3, come S3 richiede InputStream.
Ci sono pochi modi per lavorare questo fuori, ma oggetto di questa domanda è l'utilizzo di ByteArrayOutputStream.

L'idea alla base ByteArrayOutputStream è quella di utilizzare un array di byte intermidiate avvolto in Input/Output Stream in modo che il ragazzo che vuole scrivere al flusso di output scriverà alla matrice e il ragazzo che vuole leggere, leggerà la matrice.

Il mio chiedo è il motivo per cui ByteArrayOutputStream non consente alcun accesso alla matrice di byte senza copiarlo, ad esempio, per fornire un InputStream che ha accesso diretto ad esso. L'unico modo di accesso è chiamare toByteArray(), che farà una copia della matrice interna (quella standard). Il che significa, nel mio esempio immagine, avrò tre copie dell'immagine nella memoria:

  • prima è il BufferedImage reale,
  • secondo è il array interna del OutputStream e
  • terzo è la copia prodotta da toByteArray() così posso creare il InputStream.

Come questo disegno è giustificato?

  • implementazione Nascondere? Basta fornire getInputStream(), ed i soggiorni di implementazione nascosti.
  • Multi-threading? ByteArrayOutputStream non è adatto per l'accesso da più thread comunque, quindi questo non può essere.

Inoltre, c'è secondo sapore di ByteArrayOutputStream, fornito da Apache commons-io library (che ha una diversa implementazione interna). Ma entrambi hanno esattamente lo stesso pubblici di interfaccia che non fornisce modo per accedere alla matrice di byte senza copiarlo.

È stato utile?

Soluzione

Per fortuna, la matrice interna è protected, in modo da poter sottoclasse, e avvolgere un ByteArrayInputStream intorno ad esso, senza alcuna copia.

Altri suggerimenti

My wondering is why ByteArrayOutputStream does not allow any access to the byte array without coping it, for example, to provide an InputStream that has direct access to it.

I can think of four reasons:

  • The current implementation uses a single byte array, but it could also be implemented as a linked list of byte arrays, deferring the creation of the final array until the application asks for it. If the application could see the actual byte buffer, it would have to be a single array.

  • Contrary to your understanding ByteArrayOutputStream is thread safe, and is suitable for use in multi-threaded applications. But if direct access was provided to the byte array, it is difficult to see how that could be synchronized without creating other problems.

  • The API would need to be more complicated because the application also needs to know where the current buffer high water mark is, and whether the byte array is (still) the live byte array. (The ByteArrayOutputStream implementation occasionally needs to reallocate the byte array ... and that will leave the application holding a reference to an array that is no longer the array.)

  • When you expose the byte array, you allow an application to modify the contents of the array, which could be problematic.


How this design is justified?

The design is tailored for simpler use-cases than yours. The Java SE class libraries don't aim to support all possible use-cases. But they don't prevent you (or a 3rd party library) from providing other stream classes for other use-cases.


The bottom line is that the Sun designers decided NOT to expose the byte array for ByteArrayOutputStream, and (IMO) you are unlikely to change their minds.

(And if you want to try, this is not the right place to do it.

  • Try submitting an RFE via the Bugs database.
  • Or develop an patch that adds the functionality and submit it to the OpenJDK team via the relevant channels. You would increase your chances if you included comprehensive unit tests and documentation.)

You might have more success convincing the Apache Commons IO developers of the rightness of your arguments, provided that you can come up with an API design that isn't too dangerous.

Alternatively, there's nothing stopping you from just implementing your own special purpose version that exposes its internal data structures. The code is GPL'ed so you can copy it ... subject to the normal GPL rules about code distribution.

I think that the behavior you are looking for is a Pipe. A ByteArrayOutputStream is just an OutputStream, not an input/output stream. It wasn't designed for what you have in mind.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top