Merge pull request #8688 from psoares/master
[BAEL-3601] How to Lock Files in Java
This commit is contained in:
commit
242bd4f13d
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,148 @@
|
|||||||
|
package com.baeldung.lock;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
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.channels.NonReadableChannelException;
|
||||||
|
import java.nio.channels.NonWritableChannelException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
|
||||||
|
public class FileLocks {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(FileLocks.class);
|
||||||
|
|
||||||
|
// Write locks
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trying to get an exclusive lock on a read-only FileChannel won't work.
|
||||||
|
*/
|
||||||
|
static void getExclusiveLockFromInputStream() throws IOException {
|
||||||
|
Path path = Files.createTempFile("foo", "txt");
|
||||||
|
try (FileInputStream fis = new FileInputStream(path.toFile());
|
||||||
|
FileLock lock = fis.getChannel()
|
||||||
|
.lock()) {
|
||||||
|
LOG.debug("This won't happen");
|
||||||
|
} catch (NonWritableChannelException e) {
|
||||||
|
LOG.error("The channel obtained through a FileInputStream isn't writable. You can't obtain an exclusive lock on it!");
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an exclusive lock from a RandomAccessFile. Works because the file is writable.
|
||||||
|
* @param from beginning of the locked region
|
||||||
|
* @param size how many bytes to lock
|
||||||
|
* @return A lock object representing the newly-acquired lock
|
||||||
|
* @throws IOException if there is a problem creating the temporary file
|
||||||
|
*/
|
||||||
|
static FileLock getExclusiveLockFromRandomAccessFile(long from, long size) throws IOException {
|
||||||
|
Path path = Files.createTempFile("foo", "txt");
|
||||||
|
try (RandomAccessFile file = new RandomAccessFile(path.toFile(), "rw");
|
||||||
|
FileLock lock = file.getChannel()
|
||||||
|
.lock(from, size, false)) {
|
||||||
|
if (lock.isValid()) {
|
||||||
|
LOG.debug("This is a valid exclusive lock");
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquires an exclusive lock on a file region.
|
||||||
|
* @param from beginning of the locked region
|
||||||
|
* @param size how many bytes to lock
|
||||||
|
* @return A lock object representing the newly-acquired lock
|
||||||
|
* @throws IOException if there is a problem creating the temporary file
|
||||||
|
*/
|
||||||
|
static FileLock getExclusiveLockFromFileChannelOpen(long from, long size) throws IOException {
|
||||||
|
Path path = Files.createTempFile("foo", "txt");
|
||||||
|
try (FileChannel channel = FileChannel.open(path, StandardOpenOption.APPEND); FileLock lock = channel.lock(from, size, false)) {
|
||||||
|
String text = "Hello, world.";
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(text.length() + System.lineSeparator()
|
||||||
|
.length());
|
||||||
|
buffer.put((text + System.lineSeparator()).getBytes(StandardCharsets.UTF_8));
|
||||||
|
buffer.flip();
|
||||||
|
while (buffer.hasRemaining()) {
|
||||||
|
channel.write(buffer, channel.size());
|
||||||
|
}
|
||||||
|
LOG.debug("This was written to the file");
|
||||||
|
Files.lines(path)
|
||||||
|
.forEach(LOG::debug);
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read locks
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trying to get a shared lock on a write-only FileChannel won't work.
|
||||||
|
*/
|
||||||
|
static void getReadLockFromOutputStream() throws IOException {
|
||||||
|
Path path = Files.createTempFile("foo", "txt");
|
||||||
|
try (FileOutputStream fis = new FileOutputStream(path.toFile());
|
||||||
|
FileLock lock = fis.getChannel()
|
||||||
|
.lock(0, Long.MAX_VALUE, true)) {
|
||||||
|
LOG.debug("This won't happen");
|
||||||
|
} catch (NonReadableChannelException e) {
|
||||||
|
LOG.error("The channel obtained through a FileOutputStream isn't readable. " + "You can't obtain an shared lock on it!");
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a lock from an <tt>InputStream</tt>.
|
||||||
|
* @param from beginning of the locked region
|
||||||
|
* @param size how many bytes to lock
|
||||||
|
* @return A lock object representing the newly-acquired lock
|
||||||
|
* @throws IOException if there is a problem creating the temporary file
|
||||||
|
*/
|
||||||
|
static FileLock getReadLockFromInputStream(long from, long size) throws IOException {
|
||||||
|
Path path = Files.createTempFile("foo", "txt");
|
||||||
|
try (FileInputStream fis = new FileInputStream(path.toFile());
|
||||||
|
FileLock lock = fis.getChannel()
|
||||||
|
.lock(from, size, true)) {
|
||||||
|
if (lock.isValid()) {
|
||||||
|
LOG.debug("This is a valid shared lock");
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an exclusive lock from a RandomAccessFile. Works because the file is readable.
|
||||||
|
* @param from beginning of the locked region
|
||||||
|
* @param size how many bytes to lock
|
||||||
|
* @return A lock object representing the newly-acquired lock
|
||||||
|
* @throws IOException if there is a problem creating the temporary file
|
||||||
|
*/
|
||||||
|
static FileLock getReadLockFromRandomAccessFile(long from, long size) throws IOException {
|
||||||
|
Path path = Files.createTempFile("foo", "txt");
|
||||||
|
try (RandomAccessFile file = new RandomAccessFile(path.toFile(), "r"); // could also be "rw", but "r" is sufficient for reading
|
||||||
|
FileLock lock = file.getChannel()
|
||||||
|
.lock(from, size, true)) {
|
||||||
|
if (lock.isValid()) {
|
||||||
|
LOG.debug("This is a valid shared lock");
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
package com.baeldung.lock;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.FileLock;
|
||||||
|
import java.nio.channels.NonReadableChannelException;
|
||||||
|
import java.nio.channels.NonWritableChannelException;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class FileLocksUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenAnInputStream_whenGetWriteLock_thenThrowNonWritableChannelException() {
|
||||||
|
assertThrows(NonWritableChannelException.class, () -> FileLocks.getExclusiveLockFromInputStream());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenARandomAccessFileWithReadWriteAccess_whenGetWriteLock_thenLock() throws IOException {
|
||||||
|
FileLock lock = FileLocks.getExclusiveLockFromRandomAccessFile(0, 10);
|
||||||
|
assertNotNull(lock);
|
||||||
|
assertFalse(lock.isShared());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenAPath_whenGetExclusiveLock_thenLock() throws IOException {
|
||||||
|
FileLock lock = FileLocks.getExclusiveLockFromFileChannelOpen(0, 10);
|
||||||
|
assertNotNull(lock);
|
||||||
|
assertFalse(lock.isShared());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenAFileOutputStream_whenGetSharedLock_thenThrowNonReadableChannelException() {
|
||||||
|
assertThrows(NonReadableChannelException.class, FileLocks::getReadLockFromOutputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenAnInputStream_whenGetSharedLock_thenLock() throws IOException {
|
||||||
|
FileLock lock = FileLocks.getReadLockFromInputStream(0, 10);
|
||||||
|
assertNotNull(lock);
|
||||||
|
assertTrue(lock.isShared());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenARandomAccessFile_whenGetSharedLock_thenLock() throws IOException {
|
||||||
|
FileLock lock = FileLocks.getReadLockFromRandomAccessFile(0, 10);
|
||||||
|
assertNotNull(lock);
|
||||||
|
assertTrue(lock.isShared());
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user