From af27178965c50f7a3cb8c4443b98b7fb61e58a87 Mon Sep 17 00:00:00 2001 From: Philippe Soares Date: Fri, 3 Jan 2020 00:43:57 -0500 Subject: [PATCH] File locking example --- core-java-modules/core-java-io-2/README.md | 2 +- core-java-modules/core-java-nio-2/pom.xml | 17 +++ .../java/com/baeldung/lock/FileLocks.java | 105 ++++++++++++++++++ .../lock/com_baeldung_lock_FileLocks.h | 21 ++++ 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 core-java-modules/core-java-nio-2/src/main/java/com/baeldung/lock/FileLocks.java create mode 100644 core-java-modules/core-java-nio-2/src/main/java/com/baeldung/lock/com_baeldung_lock_FileLocks.h diff --git a/core-java-modules/core-java-io-2/README.md b/core-java-modules/core-java-io-2/README.md index 3251d2153e..62461be0ff 100644 --- a/core-java-modules/core-java-io-2/README.md +++ b/core-java-modules/core-java-io-2/README.md @@ -11,5 +11,5 @@ This module contains articles about core Java input and output (IO) - [List Files in a Directory in Java](https://www.baeldung.com/java-list-directory-files) - [Java – Append Data to a File](https://www.baeldung.com/java-append-to-file) - [How to Copy a File with Java](https://www.baeldung.com/java-copy-file) -- [Create a Directory in Java](https://www.baeldung.com/java-create-directory) +- [Create a Directory in Java](https://www.baeldung.com/java-create-directory) - [[<-- Prev]](/core-java-modules/core-java-io) diff --git a/core-java-modules/core-java-nio-2/pom.xml b/core-java-modules/core-java-nio-2/pom.xml index cd5c87d44e..ba50391048 100644 --- a/core-java-modules/core-java-nio-2/pom.xml +++ b/core-java-modules/core-java-nio-2/pom.xml @@ -14,5 +14,22 @@ 0.0.1-SNAPSHOT ../../parent-java + + + + + com.github.jnr + jnr-ffi + 2.1.11 + + + + + com.github.jnr + jnr-constants + 0.9.14 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-nio-2/src/main/java/com/baeldung/lock/FileLocks.java b/core-java-modules/core-java-nio-2/src/main/java/com/baeldung/lock/FileLocks.java new file mode 100644 index 0000000000..5363ba56e1 --- /dev/null +++ b/core-java-modules/core-java-nio-2/src/main/java/com/baeldung/lock/FileLocks.java @@ -0,0 +1,105 @@ +package com.baeldung.lock; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jnr.ffi.LibraryLoader; +import jnr.ffi.Memory; +import jnr.ffi.Pointer; +import jnr.ffi.types.pid_t; + +public class FileLocks { + + public static interface LibC { + + public static final int O_NONBLOCK = jnr.constants.platform.OpenFlags.O_NONBLOCK.intValue(); + public static final int O_RDWR = jnr.constants.platform.OpenFlags.O_RDWR.intValue(); + public static final int O_EXLOCK = jnr.constants.platform.OpenFlags.O_EXLOCK.intValue(); + + public long write(int fd, Pointer data, long len); + + @pid_t + long getpid(); + + int open(String filename, int flags); + + int close(int fd); + } + + public static void main(String[] args) throws IOException, InterruptedException { + + Path path = Paths.get("/tmp/foo"); + + // Delete the file if it exists + Files.deleteIfExists(path); + + // Start with a fresh empty file + Files.createFile(path); + + // Prepare some external libc calls. Will only work on systems that have libc. + LibC libc = LibraryLoader.create(LibC.class).load("c"); + byte[] bytes = "Hello from C\n".getBytes("UTF-8"); + jnr.ffi.Runtime runtime = jnr.ffi.Runtime.getRuntime(libc); + Pointer buffer = Memory.allocateDirect(runtime, bytes.length); + buffer.put(0, bytes, 0, bytes.length); + + // Open the file through a libc call. This returns a file descriptor. + int fd = libc.open(path.toString(), libc.O_RDWR + libc.O_EXLOCK + libc.O_NONBLOCK); + System.out.println("Opened the file through a libc call that locks it."); + + // Our java method will see the lock. Itd will be well behaved and won't write to the file. + // Note that external processes on POSIX systems would still be able to write to this file ignoring any locks. + writeToRandomAccessFile(path, "I won't write this", 0L); + + // Libc opened the file, it can write to its corresponding file handle. + libc.write(fd, buffer, bytes.length); + + // Now let's close the file through a libc call, to release its lock. + libc.close(fd); + System.out.println("Invoked libc's close() method"); + + // This time our method won't see the lock and will write to the file. + writeToRandomAccessFile(path, "Hello from java", bytes.length); + + System.out.println("Now that all the locks are gone, here are the file contents:"); + System.out.println("------------------------------------------------------------"); + Files.lines(path).forEach(System.out::println); + + } + + public static RandomAccessFile writeToRandomAccessFile(Path path, String data, long position) { + RandomAccessFile file = null; + try { + file = new RandomAccessFile(path.toFile(), "rws"); + FileChannel channel = file.getChannel(); + // Try to acquire a lock + try (FileLock lock = channel.tryLock()) { + if (lock == null) { + System.out.println("Tried to lock through the FileChannel's lock() method. This file is already locked! It's my responsibility to not write to it, even if the OS would let me!"); + } else { + System.out.println("I don't see a lock on this file anymore. Now I can write to it."); + int i = 0; + channel.write( + ByteBuffer.wrap((data).getBytes(StandardCharsets.UTF_8)), position); + } + } catch (Exception e) { + System.out.println("Error while locking"); + e.printStackTrace(); + } + } catch (Exception e) { + System.out.println("Other Error."); + e.printStackTrace(); + } + return file; + } + + + +} diff --git a/core-java-modules/core-java-nio-2/src/main/java/com/baeldung/lock/com_baeldung_lock_FileLocks.h b/core-java-modules/core-java-nio-2/src/main/java/com/baeldung/lock/com_baeldung_lock_FileLocks.h new file mode 100644 index 0000000000..b227cb0c79 --- /dev/null +++ b/core-java-modules/core-java-nio-2/src/main/java/com/baeldung/lock/com_baeldung_lock_FileLocks.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_baeldung_lock_FileLocks */ + +#ifndef _Included_com_baeldung_lock_FileLocks +#define _Included_com_baeldung_lock_FileLocks +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_baeldung_lock_FileLocks + * Method: getpid + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_com_baeldung_lock_FileLocks_getpid + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif