user1769197
user1769197

Reputation: 2213

How to lock a file for read and write to same file using FileInputStream and FileOutputStream

I have a process that will lock the text file and write over the same file with a new text string at random time intervals. And I have written another process, a WatchService that listens to changes in the same directory and then locks the file and reads the content of the file. I believe Locking the file is important here, as I want to make sure only one process can either read/write to the same at one time.

The code only runs successfully to lock the file and write contents to the file and the WatchService is able to detect changes in the directory but it fails to lock and read the content.

Based on the logs, it says that The process cannot access the file because another process has locked a portion of the file but I have explicitly written channel.close() to close the file channel already.

What have I done wrong? What did I misunderstand?

UPDATE: per suggestion below, I have replaced lock with tryLock and release the lock too but it's still not able to run past the line lock = channel.tryLock(); in the WatchFile class. Since it doesn't generate any error, I only found out about this through System.out.println to see where the code got stuck.

// Lock file and write 
public static void WriteTo throws IOException{
    String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss").withZone(ZoneId.of("Asia/Hong_Kong")));
    FileOutputStream fos = null;
    FileChannel channel = null;
    FileLock lock = null;
    try{
        fos = new FileOutputStream("C:\\Testing\\newTimestamp.txt");
        channel = fos.getChannel();
        lock = channel.tryLock();
        // write to channel
        byte[] mybytes = order_str.getBytes();
        fos.write(mybytes);
        System.out.println("File Successfully Written !");
    } catch(NonWritableChannelException e) {
        e.printStackTrace();
    } finally {
        lock.release();
        channel.close();
        fos.close();
    }
}
// Lock file and read contents
private static class WatchFile implements Runnable{
    public WatchFile(){

    }

    public void run() { 
        try {
            System.out.println("2. WatchService Started Running @ " + LocalDateTime.now() + " !!!");
            Path path = Paths.get("C:\\Testing");
            path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_MODIFY,StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.OVERFLOW);
            WatchKey key;
            while((key = watchService.take()) != null) {
                for(WatchEvent<?> event: key.pollEvents()) {
                    System.out.println("Event time: "+ LocalDateTime.now() + ". Event kind:" + event.kind() + ". File affected: " + event.context() +".");
                    // only register 
                    final Path changed = (Path) event.context();
                    System.out.println("Changed: " + event.context());
                    if(changed.endsWith("newTimestamp.txt") && event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {

                        String line;
                        FileInputStream fis = null;
                        FileChannel channel = null;
                        FileLock lock = null;
                        BufferedReader br = null;
                        try {
                            fis = new FileInputStream("C:\\Testing\\newTimestamp.txt");
                            channel = fis.getChannel();
                            lock = channel.tryLock();
                            br =  new BufferedReader(new InputStreamReader(fis));
                            while((line = br.readLine()) != null) {
                                // process string
                            }
                        } catch(IOException e) {
                            e.printStackTrace();
                        } finally {
                            if (br != null) {
                                try {
                                    br.close();
                                    lock.release();
                                    channel.close();
                                    fis.close();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
                key.reset();
            }

        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        } 
    }
}

Error:

java.io.IOException: The process cannot access the file because another process has locked a portion of the file
    at java.base/java.io.FileInputStream.readBytes(Native Method)
    at java.base/java.io.FileInputStream.read(FileInputStream.java:279)
    at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
    at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
    at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
    at java.base/java.io.InputStreamReader.read(InputStreamReader.java:185)
    at java.base/java.io.BufferedReader.fill(BufferedReader.java:161)
    at java.base/java.io.BufferedReader.readLine(BufferedReader.java:326)
    at java.base/java.io.BufferedReader.readLine(BufferedReader.java:392)

Upvotes: 0

Views: 506

Answers (1)

vleg1991
vleg1991

Reputation: 86

I guess you missed to release of the lock. lock.release() OR lock.close()

And it would be more suitable to use channel.tryLock() instead channel.lock()

P.S. be sure to check. Is lock acquired or not:

A lock object representing the newly-acquired lock, or null if the lock could not be acquired because another program holds an overlapping loc

Upvotes: 1

Related Questions