views:

108

answers:

4

Hi there,

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://download-llnw.oracle.com/javase/6/docs/api/java/io/FileInputStream.html#read%28%29

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

+1  A: 

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.

Andrey
I don't really understand what you're saying here.
QQQuestions
@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.
Andrey
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.
QQQuestions
@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.
Andrey
+1  A: 

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.

Seth
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...
QQQuestions
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.).
Seth
So the Javadoc is incorrect? It says it will block for FileInputStreams.
QQQuestions
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.
Seth
A: 

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.
gpeche
So you are also implying the Javadoc is incorrect, *File*InputStreams won't ever block on a read?
QQQuestions
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.
gpeche
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.
QQQuestions
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.
gpeche
A: 

You can't use files as pipes.

However you can use pipes as pipes.

EJP
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...
QQQuestions
Does it? Where does it say that?
EJP
See my initial post: Reads a byte of data from this input stream. This method blocks if no input is yet available. Via: http://download-llnw.oracle.com/javase/6/docs/api/java/io/FileInputStream.html#read%28%29
QQQuestions
Since I'm doing a read() per character, I'd say the above applies to each read() call.
QQQuestions