Ed King
Ed King

Reputation: 1863

Reading and writing files "simultaneously" in different processes

I've got two Java processes, Processor and Simulator. The Simulator writes to File X a prescribed data record (10 lines of text) every 5s. The Processor reads this file continually, waiting for tokens to indicate a valid record. The code is this (with some substitutions for filenames):

In Simulator, every 5s:

FileWriter fileWriter = new FileWriter(DATA_FILE, true);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write(DATA);
bufferedWriter.close();

In Processor, constantly:

mScanner = new Scanner(new BufferedReader(
        new FileReader(DATA_FILE)));
mScanner.useLocale(Locale.UK);

while (true) {              
    while (mScanner.hasNextLine()) {
    // Parse the data bundle.
    if (parseDataBundle()) {
            ...
        }
    }
}

Previously, the Processor was hooked to an InputStream and there was no problem using the Scanner (configured appropriately) to read data as it arrived.

Here, I can see that the data is being written correctly when it is generated by refreshing the file in Notepad. But when using a file rather than an InputStream, the if ( parseDataBundle()) { line is never reached.

What am I doing wrong? The Processor seems to have hold of the file resource, since I can't delete it whilst it's running. My gut thinks it's probably something to do with a misuse of concurrency.

Upvotes: 1

Views: 2201

Answers (2)

Bimalesh Jha
Bimalesh Jha

Reputation: 1504

Java NIO provides File locking support. Depending on the underlying OS- you can obtain exclusive lock on the file while writing and release lock after your writing is complete. Another process can try to acquire lock, if it gets, read the file and release it. Poll till you acquire lock. Hope you get the idea. Look at FileChannel#lock() API.

Upvotes: 0

Peter Lawrey
Peter Lawrey

Reputation: 533530

I would say it's a misuse of files. Files are not a designed for messaging. Once you have reached the end of the file, that is it. The only way to avoid this is to make sure you only read when you know there is more data (by checking the length) This is more complicated when using text.

You can use files with text but it is tricky. You have to have one thread polling the file size and when it changes, read just the bytes added (and no more). This can be written to a pipe. Your reading thread can read from the pipe using InputStreamReader and BufferedReader.


To vary the polling interval you can use an escalating sleep interval like

long lastSize = 
int maxSleep = 5000, sleep = 200;
while(!Thread.currentThread().isInterrupted()) {
     long size = file.length();
     if (size > lastSize) {
        copyData(size - lastSize);
        lastSize = size;
        sleep = 200;
     } else {
        Thread.sleep(sleep);
        sleep += 200;
        if (sleep > maxSleep)
            sleep = maxSleep;
}

The benefit of this approach is the that time it sleeps for adjusts to the rate it gets messages.

Upvotes: 2

Related Questions