Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to Pipe InputStream to OutputStream [duplicate]

Tags:

java

java-io

pipe

I was to trying to find the best way to pipe the InputStream to OutputStream. I don't have an option to use any other libraries like Apache IO. Here is the snippet and output.

import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.channels.FileChannel;  public class Pipe {     public static void main(String[] args) throws Exception {          for(PipeTestCase testCase : testCases) {             System.out.println(testCase.getApproach());             InputStream is = new FileInputStream("D:\\in\\lft_.txt");             OutputStream os = new FileOutputStream("D:\\in\\out.txt");              long start = System.currentTimeMillis();                         testCase.pipe(is, os);             long end = System.currentTimeMillis();              System.out.println("Execution Time = " + (end - start) + " millis");             System.out.println("============================================");              is.close();             os.close();         }      }      private static PipeTestCase[] testCases = {          new PipeTestCase("Fixed Buffer Read") {                      @Override             public void pipe(InputStream is, OutputStream os) throws IOException {                 byte[] buffer = new byte[1024];                 while(is.read(buffer) > -1) {                     os.write(buffer);                    }             }         },          new PipeTestCase("dynamic Buffer Read") {                        @Override             public void pipe(InputStream is, OutputStream os) throws IOException {                 byte[] buffer = new byte[is.available()];                 while(is.read(buffer) > -1) {                     os.write(buffer);                        buffer = new byte[is.available() + 1];                 }             }         },          new PipeTestCase("Byte Read") {                      @Override             public void pipe(InputStream is, OutputStream os) throws IOException {                 int c;                  while((c = is.read()) > -1) {                     os.write(c);                     }             }         },           new PipeTestCase("NIO Read") {                       @Override             public void pipe(InputStream is, OutputStream os) throws IOException {                 FileChannel source      = ((FileInputStream) is).getChannel();                  FileChannel destnation  = ((FileOutputStream) os).getChannel();                 destnation.transferFrom(source, 0, source.size());             }         },       }; }   abstract class PipeTestCase {     private String approach;      public PipeTestCase( final String approach) {         this.approach = approach;                }      public String getApproach() {         return approach;     }      public abstract void pipe(InputStream is, OutputStream os) throws IOException; } 

Output (~4MB input file) :

Fixed Buffer Read Execution Time = 71 millis ============================================ dynamic Buffer Read Execution Time = 167 millis ============================================ Byte Read Execution Time = 29124 millis ============================================ NIO Read Execution Time = 125 millis ============================================ 

'Dynamic Buffer Read' uses available() method. But it is not reliable as per java docs

It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream.

'Byte Read' seems to be very slow.

So 'Fixed Buffer Read' is the best option for pipe? Any thoughts?

like image 342
Sivasubramaniam Arunachalam Avatar asked Jul 30 '12 05:07

Sivasubramaniam Arunachalam


People also ask

How do I copy InputStream to OutputStream?

// take the copy of the stream and re-write it to an InputStream PipedInputStream in = new PipedInputStream(); final PipedOutputStream out = new PipedOutputStream(in); new Thread(new Runnable() { public void run () { try { // write the original OutputStream to the PipedOutputStream // note that in order for the below ...

How do you write InputStream to ByteArrayOutputStream?

The IOUtils type has a static method to read an InputStream and return a byte[] . InputStream is; byte[] bytes = IOUtils. toByteArray(is); Internally this creates a ByteArrayOutputStream and copies the bytes to the output, then calls toByteArray() .

What is the difference between InputStream and OutputStream?

An input stream is used to read data from the source. And, an output stream is used to write data to the destination.

How do I get FileReader from InputStream?

There is no way to convert the InputStream into a FileReader. What you would need to do is write the contents of the MultiPartFile into a real on-disk File, then open a FileReader to it. Well, you can certainly use an InputStreamReader to wrap a Reader around an InputStream.


2 Answers

Java 9

Since Java 9 one can use this method from InputStream:

public long transferTo(OutputStream out) throws IOException 

Pre Java 9

A one-liner from apache commons:

IOUtils.copy(inputStream, outputStream); 

Documentation here. There are multiple copy methods with different parameters. It is also possible to specify the buffer size.

like image 125
Dariusz Avatar answered Sep 18 '22 17:09

Dariusz


I came across this, and the final read can cause problems.

SUGGESTED CHANGE:

public void pipe(InputStream is, OutputStream os) throws IOException {   int n;   byte[] buffer = new byte[1024];   while((n = is.read(buffer)) > -1) {     os.write(buffer, 0, n);   // Don't allow any extra bytes to creep in, final write   }  os.close (); 

I also agree that 16384 is probably a better fixed buffer size than 1024.

IMHO...

like image 38
paulsm4 Avatar answered Sep 18 '22 17:09

paulsm4