|
| 1 | +package com.baeldung.lock; |
| 2 | + |
| 3 | +import java.io.IOException; |
| 4 | +import java.io.RandomAccessFile; |
| 5 | +import java.nio.ByteBuffer; |
| 6 | +import java.nio.channels.FileChannel; |
| 7 | +import java.nio.channels.FileLock; |
| 8 | +import java.nio.charset.StandardCharsets; |
| 9 | +import java.nio.file.Files; |
| 10 | +import java.nio.file.Path; |
| 11 | +import java.nio.file.Paths; |
| 12 | + |
| 13 | +import jnr.ffi.LibraryLoader; |
| 14 | +import jnr.ffi.Memory; |
| 15 | +import jnr.ffi.Pointer; |
| 16 | +import jnr.ffi.types.pid_t; |
| 17 | + |
| 18 | +public class FileLocks { |
| 19 | + |
| 20 | + public static interface LibC { |
| 21 | + |
| 22 | + public static final int O_NONBLOCK = jnr.constants.platform.OpenFlags.O_NONBLOCK.intValue(); |
| 23 | + public static final int O_RDWR = jnr.constants.platform.OpenFlags.O_RDWR.intValue(); |
| 24 | + public static final int O_EXLOCK = jnr.constants.platform.OpenFlags.O_EXLOCK.intValue(); |
| 25 | + |
| 26 | + public long write(int fd, Pointer data, long len); |
| 27 | + |
| 28 | + @pid_t |
| 29 | + long getpid(); |
| 30 | + |
| 31 | + int open(String filename, int flags); |
| 32 | + |
| 33 | + int close(int fd); |
| 34 | + } |
| 35 | + |
| 36 | + public static void main(String[] args) throws IOException, InterruptedException { |
| 37 | + |
| 38 | + Path path = Paths.get("/tmp/foo"); |
| 39 | + |
| 40 | + // Delete the file if it exists |
| 41 | + Files.deleteIfExists(path); |
| 42 | + |
| 43 | + // Start with a fresh empty file |
| 44 | + Files.createFile(path); |
| 45 | + |
| 46 | + // Prepare some external libc calls. Will only work on systems that have libc. |
| 47 | + LibC libc = LibraryLoader.create(LibC.class).load("c"); |
| 48 | + byte[] bytes = "Hello from C\n".getBytes("UTF-8"); |
| 49 | + jnr.ffi.Runtime runtime = jnr.ffi.Runtime.getRuntime(libc); |
| 50 | + Pointer buffer = Memory.allocateDirect(runtime, bytes.length); |
| 51 | + buffer.put(0, bytes, 0, bytes.length); |
| 52 | + |
| 53 | + // Open the file through a libc call. This returns a file descriptor. |
| 54 | + int fd = libc.open(path.toString(), libc.O_RDWR + libc.O_EXLOCK + libc.O_NONBLOCK); |
| 55 | + System.out.println("Opened the file through a libc call that locks it."); |
| 56 | + |
| 57 | + // Our java method will see the lock. Itd will be well behaved and won't write to the file. |
| 58 | + // Note that external processes on POSIX systems would still be able to write to this file ignoring any locks. |
| 59 | + writeToRandomAccessFile(path, "I won't write this", 0L); |
| 60 | + |
| 61 | + // Libc opened the file, it can write to its corresponding file handle. |
| 62 | + libc.write(fd, buffer, bytes.length); |
| 63 | + |
| 64 | + // Now let's close the file through a libc call, to release its lock. |
| 65 | + libc.close(fd); |
| 66 | + System.out.println("Invoked libc's close() method"); |
| 67 | + |
| 68 | + // This time our method won't see the lock and will write to the file. |
| 69 | + writeToRandomAccessFile(path, "Hello from java", bytes.length); |
| 70 | + |
| 71 | + System.out.println("Now that all the locks are gone, here are the file contents:"); |
| 72 | + System.out.println("------------------------------------------------------------"); |
| 73 | + Files.lines(path).forEach(System.out::println); |
| 74 | + |
| 75 | + } |
| 76 | + |
| 77 | + public static RandomAccessFile writeToRandomAccessFile(Path path, String data, long position) { |
| 78 | + RandomAccessFile file = null; |
| 79 | + try { |
| 80 | + file = new RandomAccessFile(path.toFile(), "rws"); |
| 81 | + FileChannel channel = file.getChannel(); |
| 82 | + // Try to acquire a lock |
| 83 | + try (FileLock lock = channel.tryLock()) { |
| 84 | + if (lock == null) { |
| 85 | + 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!"); |
| 86 | + } else { |
| 87 | + System.out.println("I don't see a lock on this file anymore. Now I can write to it."); |
| 88 | + int i = 0; |
| 89 | + channel.write( |
| 90 | + ByteBuffer.wrap((data).getBytes(StandardCharsets.UTF_8)), position); |
| 91 | + } |
| 92 | + } catch (Exception e) { |
| 93 | + System.out.println("Error while locking"); |
| 94 | + e.printStackTrace(); |
| 95 | + } |
| 96 | + } catch (Exception e) { |
| 97 | + System.out.println("Other Error."); |
| 98 | + e.printStackTrace(); |
| 99 | + } |
| 100 | + return file; |
| 101 | + } |
| 102 | + |
| 103 | + |
| 104 | + |
| 105 | +} |
0 commit comments