Internal working of byte streams. Difference between write(65) and write('A')?

295 Views Asked by At

Both of these lines will write me letter A in a file. Can someone tell me how are they different in internal working?

FileOutputStream fileOutputStream = new FileOutputStream("test.txt");
fileOutputStream.write(65);
fileOutputStream.write('A');

[EDIT]: I am more interested in how converting works in both of these cases. As I know what ASCII and UNICODE tables are.

1

There are 1 best solutions below

0
On BEST ANSWER

Let's start with the javadoc for FileOutputStream. If you look at it you will see that there are three write methods:

  • void write​(byte[] b) - Writes b.length bytes from the specified byte array to this file output stream.
  • void write​(byte[] b, int off, int len) - Writes len bytes from the specified byte array starting at offset off to this file output stream.
  • void write​(int b) - Writes the specified byte to this file output stream.

So what does it tell us?

  1. Clearly, when we call fileOutputStream.write(65) or fileOutputStream.write('A'), we are NOT calling the first or second overloads of the write method. We are actually calling the third one.

  2. Therefore when we call fileOutputStream.write('A'), the char value 'A' is converted to an int value. This conversion is a primitive widening conversion from char to int. It is equivalent to doing an explicit type cast; i.e (int) 'A'.

  3. Primitive widening casts from an integer type (e.g. char) to a larger integer type (e.g. int) is simply a matter of making it bigger. In this case we just add 16 zero bits on the front. (Because char is unsigned and int is signed.)

  4. When we look at the ASCII and Unicode code tables we see that they both use the same value for the letter capital A. It is 65 in decimal or 41 in hexadecimal. In other words (int) 'A' and 65 are the same value.

  5. So when you take the implicit widening conversion that happens, fileOutputStream.write('A') and fileOutputStream.write(65) are actually calling write with the same parameter value.

  6. Finally, the javadoc for write(int) refers to this javadoc which says:

    Writes the specified byte to this output stream. The general contract for write is that one byte is written to the output stream. The byte to be written is the eight low-order bits of the argument b. The 24 high-order bits of b are ignored.

    That explains how the int magically turns into a byte.


Note that this only prints something sensible because we picked a character in the ASCII character set. It so happens that Unicode chose to mirror the ASCII character set as the first 128 Unicode codepoints.

If you replaced A with some character outside of the ASCII charset, there is a good chance that OutputStream::write(int) would garble it.

It is better to use a FileWriter rather than a FileOutputStream when outputting text.