mishar
mishar

Reputation: 455

Why do write() and read() appear to write and read more than a byte?

In Java, the maximum value that a byte can hold is 127, which is 8 bits. Also, the read() method that FileInputStream uses (which it inherits from InputStream) states that it only reads one byte, and the write() method that FileOutputStream uses (which it inherits from OutputStream) states that it only writes one byte. However, when I pass a number greater than 127 but less than 256 to write() and then read() it, I get a character with a decimal value that is indeed between 127 and 255. This seems to show that write() can actually write 9 bits instead of 8, and that read() can actually read 9 bits instead of 8. So, my question is how is this possible? How can read() read more than a byte and how can write() write more than a byte? Is there something else I'm missing?

As a further example, say I pass the integer 1000 to write(). write() then outputs a character, which read() then reads as having a decimal value of 232. This seems to occur because 1000 - 512 - 256 = 232, which again seems to show that write() and read() write and read 9 bits (up to 255) rather than a byte (8 bits, of up to 127). As it seems to me, write() is writing the lower 9 bits of 1000, which read() then reads, which in this case gives 232.

I have posted the program I'm using to test this all out. Also, I am fairly new to Java, so any help or thoughts are much appreciated!

import java.io.*;

public class TestingCharsAndBytes 
{

    public static void main(String[] args) 
    {

        FileOutputStream output = null;
        FileInputStream input = null;       
        try
        {
            output = new FileOutputStream(".../testFileIO1.txt");
            input = new FileInputStream(".../testFileIO1.txt");

            // Stuff to try:


            doFileResult(512,output,input);
            doFileResult(128,output,input);
            doFileResult(256,output,input);
            doFileResult(257,output,input);
            doFileResult(160,output,input);
            doFileResult(289,output,input);
            doFileResult(1000,output,input);
            doFileResult(2000,output,input);            
        }
        catch(IOException e)
        {
            System.out.println("Error occurred.");
            e.getStackTrace();
        }
        finally
        {
            try
            {
                output.close();
                input.close();
            }
            catch(Exception e)
            {
                System.out.println("Error closing file.");
            }           
        }
    }   
    public static void doFileResult(int toWrite, FileOutputStream outStream, FileInputStream inputStream) throws IOException
    {
        System.out.println("******************");
        outStream.write(toWrite);

        int x = inputStream.read();
        char y = (char) x;

        System.out.println("Integer passed to write: " + toWrite);
        System.out.println("Input integer read: " + x);
        System.out.println("Input character read (after casting to char): " + y);
        System.out.println();       
    }
}

Upvotes: 1

Views: 713

Answers (1)

Andy Turner
Andy Turner

Reputation: 140319

Per the documentation, read() uses -1 as a special value to indicate EOF. If the actual range of byte (-128..127) were used, -1 would be a valid byte.

As stated in the documentation of the base method, InputStream.read():

The value byte is returned as an int in the range 0 to 255. If no byte is available because the end of the stream has been reached, the value -1 is returned.

The idiomatic way to write code reading from a stream is something like:

while (true) {
  int v = stream.read();
  if (v == -1) {
    break;
  }
  byte b = (byte) v;
  // Do something.
}

The cast to byte will "correctly" map the int 0..255 into the byte -128..127, because a narrowing cast from 32 to 8 bits will simply keep the 8 least significant bits.

Upvotes: 3

Related Questions