Why is the FileInputStream read() not blocking?
Asked Answered
S

5

6

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

Shawm answered 9/9, 2010 at 15:4 Comment(2)
when you write to disk you force an EOF, no? the EOF only gets moved as you append new info. But the block on the disk has to have an EOF...Cluj
So you are saying the EOF is always written because a file always needs one. But I thought an EOF is only written at the end after flushing and closing of the file. But that means my read() will never block when reading a file because there is always an EOF and always return a -1 even if the file is empty. Thus is the JavaDoc incorrect?Shawm
O
2

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.
Owings answered 9/9, 2010 at 21:16 Comment(5)
So you are also implying the Javadoc is incorrect, FileInputStreams won't ever block on a read?Shawm
No, javadoc says that InputStreams will block if input data is not available. What I am saying is that FileInputStreams always have input available, and so, according to javadoc, they do not need to block. Technically, they might still block in some corner cases, such as reading from a file with a FileLock, but that does not seem to be this case.Owings
Call me picky, but then the docs should have said that, now it can be read (by me :) as that it is always blocking if no input available yet. I'm suprised that it sees an EOF before the file is closed, but apparently (as per the very first comment of my original post), there will always be an EOF and that one can thus always be read.Shawm
Well, in a file, EOF exists no matter what. You create a new file -> EOF is at "position" 0. You then write 3 new characters -> EOF moves to "position" 3, etc. So there is always at least EOF available. This is not really Java specific, it will work that way for most (all?) mainstream languages.Owings
The doc does say: Returns: the next byte of data, or -1 if the end of the file is reached.Tully
N
1

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.

Nazarene answered 9/9, 2010 at 15:17 Comment(4)
Are you saying that my read() is at the end of the stream? Why would it be? The Writer is still there and has the file/stream open. And what would be an example when the FileInputStream.read() will block? Example code would be great...Shawm
That's exactly what I'm saying. I can't imagine FileInputStream.read() will ever block for a significant amount of time for a local file read. Blocking is something that will usually happen on other kinds of InputStreams that are abstractions of things with higher latency (socket reads, etc.).Nazarene
So the Javadoc is incorrect? It says it will block for FileInputStreams.Shawm
The javadoc says that FileInputStream.read() will block if no input is available. In 99% of cases, there's always input available, whether it be data bytes or an EOF. The 1% is for things like files on a network-mounted drive with some latency.Nazarene
G
1

You can't use files as pipes.

However you can use pipes as pipes.

Granger answered 9/9, 2010 at 23:55 Comment(5)
Yes I guess the behaviour I'm looking for is pipe-behaviour. But my question is why it doesn't block, while the Javadoc says it does block...Shawm
Does it? Where does it say that?Granger
See my initial post: Reads a byte of data from this input stream. This method blocks if no input is yet available. Via: download-llnw.oracle.com/javase/6/docs/api/java/io/…Shawm
Since I'm doing a read() per character, I'd say the above applies to each read() call.Shawm
If it didn't block there was data available.Granger
B
0

you slightly didn't catch what is blocking. Blocking IO is ones that block execution of program until IO operation finish. close just disconnect program from file. If you want one app to block another you should use some sort of synchronization.

Boroughenglish answered 9/9, 2010 at 15:12 Comment(4)
I don't really understand what you're saying here.Shawm
@qqquestions ok. This assumption: "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)." is completely incorrect. Reader/writer do not block each other. (Only in case you try to read/write single file simultaneously, but is not the case here). google "non blocking io in java", you will find articles that explain my answer in details.Boroughenglish
Why do you say my 2 programs are not read/writing the same single file simultaneously? Or do you mean exactly at the same time? I googled for your suggested keywords but that provided me no new insights, only hits explaining what non-blocking IO is. Are you saying my writer and reader are nonblocking? But why does the JavaDoc then say the read() should be blocking ("This method blocks if no input is yet available") and how can it even be reading the file while it has no EOF written yet? And I want my read() to block as the Java Doc says it should, I don't want non-blocking IO.Shawm
@qqquestions yes, they don't read-write simultaneously. Read is period between read() was called and it returned value, not between opening and closing stream. Yes, exactly at the same time. Your IO is blocking, because it blocks your application, like if you try to read from console when user didn't enter anything then your application will get blocked.Boroughenglish
E
0

You may need something to delay the actual reading of data. Check this source code : http://www.java2s.com/Open-Source/Java/Web-Server/Jigsaw/org/w3c/jigsaw/ssi/DelayedInputStream.java.htm.

Eardrum answered 22/5, 2012 at 14:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.