Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use NIO to write InputStream to File?

I am using following way to write InputStream to File:

private void writeToFile(InputStream stream) throws IOException {
    String filePath = "C:\\Test.jpg";
    FileChannel outChannel = new FileOutputStream(filePath).getChannel();       
    ReadableByteChannel inChannel = Channels.newChannel(stream);
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    
    while(true) {
        if(inChannel.read(buffer) == -1) {
            break;
        }
        
        buffer.flip();
        outChannel.write(buffer);
        buffer.clear();
    }
    
    inChannel.close();
    outChannel.close();
}

I was wondering if this is the right way to use NIO. I have read a method FileChannel.transferFrom, which takes three parameter:

  1. ReadableByteChannel src
  2. long position
  3. long count

In my case I only have src, I don't have the position and count, is there any way I can use this method to create the file?

Also for Image is there any better way to create image only from InputStream and NIO?

Any information would be very useful to me. There are similar questions here, in SO, but I cannot find any particular solution which suites my case.

like image 685
Tapas Bose Avatar asked May 16 '13 07:05

Tapas Bose


People also ask

How do you write an InputStream to a file?

InputStream to File using Apache Commons First, we create a File instance pointing to the desired path on the disk. Next, we use the copyInputStreamToFile method to read bytes from InputStream and copy into the given file.

How do you write ByteArrayInputStream to a file?

ByteArrayInputStream stream = <<Assign stream>>; byte[] bytes = new byte[1024]; stream. read(bytes); BufferedWriter writer = new BufferedWriter(new FileWriter(new File("FileLocation"))); writer. write(new String(bytes)); writer. close();

How do you write InputStream to OutputStream?

transferTo() Method. In Java 9 or higher, you can use the InputStream. transferTo() method to copy data from InputStream to OutputStream . This method reads all bytes from this input stream and writes the bytes to the given output stream in the original order.

Can we get file name from InputStream?

This information can't be extracted from InputStream . This information can only be extracted based on the filePath (and with little help of java. io. File to easily get the filename).


2 Answers

I would use Files.copy

Files.copy(is, Paths.get(filePath));

as for your version

  1. ByteBuffer.allocateDirect is faster - Java will make a best effort to perform native I/O operations directly upon it.

  2. Closing is unreliable, if first fails second will never execute. Use try-with-resources instead, Channels are AutoCloseable too.

like image 142
Evgeniy Dorofeev Avatar answered Oct 12 '22 02:10

Evgeniy Dorofeev


No it's not correct. You run the risk of losing data. The canonical NIO copy loop is as follows:

while (in.read(buffer) >= 0 || buffer.position() > 0)
{
  buffer.flip();
  out.write(buffer);
  buffer.compact();
}

Note the changed loop conditions, which take care of flushing the output at EOS, and the use of compact() instead of clear(), which takes care of the possibility of short writes.

Similarly the canonical transferTo()/transferFrom() loop is as follows:

long offset = 0;
long quantum = 1024*1024; // or however much you want to transfer at a time
long count;
while ((count = out.transferFrom(in, offset, quantum)) > 0)
{
    offset += count;
}

It must be called in a loop, as it isn't guaranteed to transfer the entire quantum.

like image 20
user207421 Avatar answered Oct 12 '22 02:10

user207421