Skip to content

Commit 748bafd

Browse files
committed
File locking example
1 parent e5cb222 commit 748bafd

4 files changed

Lines changed: 144 additions & 1 deletion

File tree

core-java-modules/core-java-io-2/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ This module contains articles about core Java input and output (IO)
1111
- [List Files in a Directory in Java](https://www.baeldung.com/java-list-directory-files)
1212
- [Java – Append Data to a File](https://www.baeldung.com/java-append-to-file)
1313
- [How to Copy a File with Java](https://www.baeldung.com/java-copy-file)
14-
- [Create a Directory in Java](https://www.baeldung.com/java-create-directory)
14+
- [Create a Directory in Java](https://www.baeldung.com/java-create-directory)
1515
- [[<-- Prev]](/core-java-modules/core-java-io)

core-java-modules/core-java-nio-2/pom.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,22 @@
1414
<version>0.0.1-SNAPSHOT</version>
1515
<relativePath>../../parent-java</relativePath>
1616
</parent>
17+
18+
<dependencies>
19+
<!-- https://mvnrepository.com/artifact/com.github.jnr/jnr-ffi -->
20+
<dependency>
21+
<groupId>com.github.jnr</groupId>
22+
<artifactId>jnr-ffi</artifactId>
23+
<version>2.1.11</version>
24+
</dependency>
25+
26+
<!-- https://mvnrepository.com/artifact/com.github.jnr/jnr-constants -->
27+
<dependency>
28+
<groupId>com.github.jnr</groupId>
29+
<artifactId>jnr-constants</artifactId>
30+
<version>0.9.14</version>
31+
</dependency>
32+
33+
</dependencies>
1734

1835
</project>
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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+
}

core-java-modules/core-java-nio-2/src/main/java/com/baeldung/lock/com_baeldung_lock_FileLocks.h

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)