CodeGym /Courses /Java Core /InputStream/OutputStream

InputStream/OutputStream

Java Core
Level 8 , Lesson 4
Available

"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?"

"Exactly."

"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.
 outputStream.close();
}

"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 (22)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
Sansho Level 19, Bordeaux, France
23 June 2021
Well since Java 9 we can use "byte[] buffer = inputstream.readAllBytes();", but as the CodeGym's robot validator use only Java 8, you'll get a CodeGym's server compile error: "cannot find symbol symbol: method readAllBytes() location: variable inputStream of type java.io.FileInputStream "
Gellert Varga Level 23, Szekesfehervar, Hungary
24 June 2021
Thanks for the information, always good to know about such innovations!:)
Олег Байбула Level 32, Ukraine Expert
16 February 2023
At least it's not Java 5.
Daniel Ketcheson Level 28, Canada
26 November 2023
The Java 5 > Java 8 equivalent is:

byte[] ourByteArray = new byte[inputStream.available()]
inputStream.read(ourByteArray);
In case you run into this in the wild
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.
Daniel Walbolt Level 22, Waterville, United States
19 July 2020
I believe what you're talking about is when the code sample has a comment saying reading into the buffer. In this case, it just means that we are reading from the file and saving the data into a byte (widened to int) array for storage. In that context, it is different from "read from" because that would just mean we're reading from a source (in that case the buffer that stores the data from the file, but in other cases a file itself).
Henrique Level 41, São Paulo, Brazil
20 July 2020
Yes, I'm referring to "reading into the buffer". Thanks for your words, it was helpful!
Gellert Varga Level 23, Szekesfehervar, Hungary
24 June 2021
"reading into the buffer= reading from the file and saving the data into a byte (widened to int) array for storage." It is not a byte array widened to an int, but an ordinary byte array. Yes, it's true the read() method of the InputStream reads one byte and returns it as a widened real int value. This will give it a value between 0 and 255, because that's the range of a byte (two on the eighth power). But Java has signed primitives, so one of the 8 bits of the byte type is always taken up by the sign bit. It occupies the first bit, "most significante bit" = MSB. After all this the byte type can only have the range of values of "two on the seventh power"= between -128 and +127. When using the read(buffer) method to read into a byte array, it won't send int values into the byte array, but only bytes. Now they are not widened to int. It is worth testing, if you print out this byte array, it will contain also minus values. Between -128 and 127. The read() method returns the bytes as int-s between 0-255, and the read(buffer) method puts byte types into the buffer between -128 and 127. This negative byte has not changed! It is still the same sequence of bits as when it was returned as a positive int. It's just that JVM now interprets it as a byte type, and therefore now can see it as a negative number. If we want to get back the normal int value from one of the minus elements of the byte array that the read() method would have given, it can be restored with this trick:

// When this character is read: 'É', the read() method will return this int value: 201
int i = 201; 
byte b = (byte) i;  // by the read(buffer) method, this is the value which will be stored in the buffer:
System.out.println("b = " + b);  // b = -55

// this trick restores the original value:
int i2 = b & 0xFF;
System.out.println("i2 = " + i2);  // i2 = 201
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.
Darko Jakimovski Level 18, Kriva Palanka, Macedonia, The Former Yugoslav Republic of
6 June 2019
I think you might be confusing read() and readLine(). The first one returns a byte that is widened into an int and the second one returns the whole line as a String representation. Also the second one is not for files.
Henk Level 19, Pretoria, South-Africa
6 June 2019
oh....So is there nothing that can read a whole line at once from a file into a String variable ? thanks :)
Darko Jakimovski Level 18, Kriva Palanka, Macedonia, The Former Yugoslav Republic of
6 June 2019
You can, like this

BufferedReader br = new BufferedReader(new FileReader(file));
String s = br.readLine();
It's like the BufferedReader we use for user input but instead of user input we take the File as input. I misspoke in the above comment
Henk Level 19, Pretoria, South-Africa
6 June 2019
cool. Yeah, I think when I revisit older posts from a couple of days ago, I get confused and forget that I actually have used the above already, lol! Chat later
Jan kirk Level 19, Venkatagiri, India
24 July 2019
As I understood it, the stream reads the file/buffer character by character; the int parameter holds the ASCII Decimal Code of the present character.
// 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.
Darko Jakimovski Level 18, Kriva Palanka, Macedonia, The Former Yugoslav Republic of
6 June 2019
Where did you go bruh? Haven't seen you in a while
Profj Level 20, Lagos, Nigeria
27 June 2019
Solid advice and taken to heart. Thanks bro!
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.
Ivan Level 22, Nope, Bulgaria
21 February 2020
Thank you, Sir! Always good to learn more!
Andrei Level 41
12 January 2021
Some gangster stuff right there!