Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the FileInputStream read() not blocking?

I've got a Writer program that writes one line of text to a file, then waits until the user hits return before it writes another line and then exits. Only after that is the file closed. The code:

public class Writer {

    Writer() {
    }

    public static String[] strings = 
        {
            "Hello World", 
            "Goodbye World"
        };

    public static void main(String[] args) 
        throws java.io.IOException {

        java.io.FileOutputStream pw =
            new java.io.FileOutputStream("myfile.txt");

        for(String s : strings) {
            pw.write(s.getBytes());
            System.in.read();
        }

        pw.close();
    }
}

Start first with:

java Writer

Then I also have a reader program that should (well I expected) block as long as the writing of the file hasn't finished yet (i.e pw.close() has not been called yet). The code:

public class ReaderFIS extends Object {

    ReaderFIS() {
    }

    public static void main(String[] args) throws Exception {

        java.io.FileInputStream in = new java.io.FileInputStream("myfile.txt");

        int ch = -1;
        while((ch = in.read()) >= 0) {
         System.out.println("ch = " + ch);
     }
        System.out.println("Last ch = " + ch);

     System.out.println("exiting");
    }
}

Start with:

java ReaderFIS

Now I expected the read() to block after reading the first "Hello World" text, based on this in the Javadoc documentation:

Reads a byte of data from this input stream. This method blocks if no input is yet available. Via: http://docs.oracle.com/javase/6/docs/api/java/io/FileInputStream.html#read()

But the ReaderFIS is immediately done after reading "Hello World" and apparently sees an EOF! So it does not block! It dumps the character values, then a -1 and then prints "exiting".

Output: ch = 72 ch = 101 ch = 108 ch = 108 ch = 111 ch = 32 ch = 87 ch = 111 ch = 114 ch = 108 ch = 100 Last ch = -1 exiting

Other variations I tried were: reading via a getChannel(), checking via getChannel() if it can be lock()ed, using available(), trying read() using a buffer, trying readLine(), continously writing a character in the file with a 500msec pause in between each write, not writing anything just keeping the file open in the Writer.
None of these variations cause the ReaderFIS program to block, it always finishes.

Why does the reader program not block? Did I miss something soooo very obvious? It seems the ReaderFIS program finds an EOF (-1) but why? The file has not been closed yet by the Writer program.

"Funny" sidenote: the System.in.read() is blocking! (and waiting for the user to hit Enter).

PS: tried this on Windows XP and Suse Linux. On Windows I can't delete the file while the writer is running (which is as I expected).

Regards, Marco

like image 952
QQQuestions Avatar asked Sep 09 '10 15:09

QQQuestions


People also ask

Is InputStream read blocking?

According to the java api, the InputStream. read() is described as: If no byte is available because the end of the stream has been reached, the value -1 is returned. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.

What is FileInputStream read in Java?

FileInputStream is meant for reading streams of raw bytes such as image data. For reading streams of characters, consider using FileReader. Constructors of FileInputStream Class. 1. FileInputStream(File file): Creates an input file stream to read from the specified File object.

What is file streams in Java?

Java FileInputStream class obtains input bytes from a file. It is used for reading byte-oriented data (streams of raw bytes) such as image data, audio, video etc. You can also read character-stream data.


3 Answers

FileInputStream always has input available: either there are bytes left to read or there is an EOF, but in general it will not block when reading. You can get blocked when you are:

  • reading from a console / terminal
  • reading from the network
  • reading from a pipe
  • reading from whatever stream that is waiting for data.

File Streams do not have to wait for data as they always have data available: in your case read() will get, basically at random, one of:

  • the old version of the file
  • the new version of the file
  • half-updated version of the file.
like image 52
gpeche Avatar answered Nov 18 '22 10:11

gpeche


Your reader program is just going to read whatever is in the file, then hit the end and return -1. If all it contains at the time you run it is "Hello World", then that's all it will be able to read. If you run it again after you've hit enter in your writer, you should see "Hello World Goodbye World".

Having no more bytes available and hitting the end of a stream are two different things. That's why System.in.read() blocks and FileInputStream.read() doesn't.

like image 36
Seth Avatar answered Nov 18 '22 10:11

Seth


You can't use files as pipes.

However you can use pipes as pipes.

like image 1
user207421 Avatar answered Nov 18 '22 10:11

user207421