Java Core
Level 8 , Lesson 4

"Hello, Amigo! Today we're going to once again dig into how InputStream and OutputStream work. The initial explanation was actually a little simplistic. These are not interfaces. They are abstract classes, and they even have a couple of implemented methods. Let's take a look at the methods they have:"

InputStream methods What the method does
int read(byte[] buff);
This method immediately reads a block of bytes into the buffer (byte array), until the buffer is full or until the source doesn't have any more bytes to read.
The method returns the number of bytes actually read (which can be less than the length of the array)
int read();
This method reads one byte and returns it. The result is widened to an int for looks. If there are no more bytes to read, the method returns -1.
int available();
This method returns the number of unread (available) bytes.
void close();
This method «closes» the stream. You call this when you're done working with the stream.
The object then performs the housekeeping operations needed to close the file, etc.
At this point, you can't read any more data from the stream.

"So we can read not only single bytes, but also whole blocks?"


"Can we also write whole blocks?"

"Yes, check it out:"

OutputStream methods What the method does
void write(int c);
This method writes one byte. The int type is narrowed to a byte. The extra part is simply discarded.
void write(byte[] buff);
This method writes a block of bytes.
void write(byte[] buff, int from, int count);
This method writes part of a block of bytes. It is used in cases when the byte array may not have been filled entirely.
void flush();
If the stream is internally storing any data that has not yet been written, this method forces it to be written.
void close();
This method «closes» the stream. You call this when you're done working with the stream.
The object then performs the housekeeping operations needed to close the file, etc. You can't write data to the stream any longer, and flush is called automatically.

"What would the file copying code look like if we read whole blocks at a time instead of single bytes?"

"Hmm. Something like this:"

Copy a file on disk
public static void main(String[] args) throws Exception
 //Create a stream to read bytes from a file
 FileInputStream inputStream = new FileInputStream("c:/data.txt");
 //Create a stream to write bytes to a file
 FileOutputStream outputStream = new FileOutputStream("c:/result.txt");

  byte[] buffer = new byte[1000];
 while (inputStream.available() > 0) //as long as there are unread bytes
  //Read the next block of bytes into buffer, and store the actual number of bytes read in count.
  int count = inputStream.read(buffer);
  outputStream.write(buffer, 0, count); //Write a block (part of a block) to the second stream

 inputStream.close(); //Close both streams. We don't need them any more.

"I understand everything about the buffer, but what's this count variable?"

"When we read the latest block of data from a file, we may get, say, 328 bytes instead of 1000. So when we write the data, we need to indicate that we're not writing the entire block—only the first 328 bytes."

When we read the last block, the read method will return the number of bytes actually read. 1000 every time we read a block, except for the last block, when we get 328.

So when we write a block, we indicate that not all of the bytes in the buffer should be written, just 328 (i.e. the value stored in the count variable).

"Now it's all clear. Thanks, Ellie."

Comments (17)
Sela Level  20, Poland
13 September 2020
notice that although InputStream and OutputStream are abstract classes most of the methods are concrete. examples demonstrate the use of one of the descendants i.e. FileInputStream and FileOutputStream because abstract classes cannot be instantiated.
Henrique Level  41, São Paulo, Brazil
17 June 2020
Hey, friends. Could somebody help me here? What does "read into" mean? Is it the same as "read from", or is it something different? My mother tongue is not English, so I'm not fully understanding this language construction... Thanks.
Darko Jakimovski Level  18, Kriva Palanka, Macedonia, The Former Yugoslav Republic of
6 June 2019
available() Returns an estimate of the number of remaining bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream. This could cause bugs when using larger files in a larger application
Henk Level  19, Pretoria, South-Africa
3 June 2019
Still cannot understand how I read a string from a file, and it's put into an Integer.
// Java Poser Level  18, Cincinnati, United States
21 May 2019
Warning: You should play around with this(copy the example and run it, change it etc.) before you go on. Make sure you understand what's going on otherwise you're gonna have a hard time the rest of the way.
Roy Level  22, Bangkok, Thailand
7 May 2019
Its important to understand that the bytes written to the buffer happen at once, so you can omit the loop when you already know the buffer is equal to or bigger than the file. This confused me a lot after this lecture, as i thought it was written byte per byte into the buffer using the loop.

  byte[] buffer = new byte[1000];
 while (inputStream.available() > 0) //  This loop can be omitted, its completely useless.
  //Read the next block of bytes into buffer <-- This line is what made me believe it was writing block by block every loop run. However,  ALL bytes are written in the buffer when the buffer is >= inputFile.
  int count = inputStream.read(buffer);    // ALL THE BYTES WILL BE READ INTO BUFFER AT ONCE
  outputStream.write(buffer, 0, count); //Write a block (part of a block) to the second stream

So using a buffer with the size of the whole file(or bigger) e.g.: byte[] buffer = new byte[inputstream.available()]; will be written to the buffer at once and thus wont be needed to be placed inside a loop. tldr; buffer >= intputfile, all will be written to buffer at once, omit loop.