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

bacar
  • 9,761
  • 11
  • 55
  • 75
QQQuestions
  • 736
  • 8
  • 7
  • 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... – jcolebrand Sep 09 '10 at 15:10
  • 1
    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? – QQQuestions Sep 09 '10 at 16:29

5 Answers5

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.
gpeche
  • 21,974
  • 5
  • 38
  • 51
  • 1
    So you are also implying the Javadoc is incorrect, *File*InputStreams won't ever block on a read? – QQQuestions Sep 13 '10 at 08:49
  • 1
    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 Sep 13 '10 at 10:01
  • 1
    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 Sep 13 '10 at 13:27
  • 1
    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 Sep 13 '10 at 16:00
  • The doc _does_ say: `Returns: the next byte of data, or -1 if the end of the file is reached.` – bacar Jul 15 '14 at 11:33
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.

Seth
  • 5,596
  • 8
  • 42
  • 56
  • 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 Sep 09 '10 at 15:35
  • 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 Sep 09 '10 at 18:50
  • So the Javadoc is incorrect? It says it will block for FileInputStreams. – QQQuestions Sep 13 '10 at 08:46
  • 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 Sep 13 '10 at 18:57
1

You can't use files as pipes.

However you can use pipes as pipes.

user207421
  • 305,947
  • 44
  • 307
  • 483
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.

Stephan
  • 41,764
  • 65
  • 238
  • 329
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.

Andrey
  • 59,039
  • 12
  • 119
  • 163
  • I don't really understand what you're saying here. – QQQuestions Sep 09 '10 at 15:39
  • @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 Sep 09 '10 at 16:02
  • 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 Sep 09 '10 at 16:23
  • @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 Sep 09 '10 at 16:38