I’m having a hard time finding the correct way to do any advanced file-system operations on Linux using Scala.
The one which I really can’t figure out if best described by the following pseudo-code:
with fd = open(path, append | create): with flock(fd, exclusive_lock): fd.write(string)
Basically open a file in append mode (create it if it’s non existent), get an exclusive lock to it and write to it (with the implicit unlock and close afterwards).
Is there an easy, clean and efficient way of doing this if I know my program will be ran on linux only ? (preferably without glancing offer the exceptions that should be handled).
Edit:
The answer I got is, as far as I’ve seen and tested is correct. However it’s quite verbose, so I’m marking it as ok but I’m leaving this snippet of code here, which is the one I ended up using (Not sure if it’s correct, but as far as I see it does everything that I need):
val fc = FileChannel.open(Paths.get(file_path), StandardOpenOption.CREATE, StandardOpenOption.APPEND) try { fc.lock() fc.write(ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8))) } finally { fc.close() }
Advertisement
Answer
You can use FileChannel.lock and FileLock to get what you wanted:
import java.nio.ByteBuffer import java.nio.channels.FileChannel import java.nio.charset.StandardCharsets import java.nio.file.{Path, Paths, StandardOpenOption} import scala.util.{Failure, Success, Try} object ExclusiveFsWrite { def main(args: Array[String]): Unit = { val path = Paths.get("/tmp/file") val buffer = ByteBuffer.wrap("Some text data here".getBytes(StandardCharsets.UTF_8)) val fc = getExclusiveFileChannel(path) try { fc.write(buffer) } finally { // channel close will also release a lock fc.close() } () } private def getExclusiveFileChannel(path: Path): FileChannel = { // Append if exist or create new file (if does not exist) val fc = FileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.APPEND, StandardOpenOption.CREATE) if (fc.size > 0) { // set position to the end fc.position(fc.size - 1) } // get an exclusive lock Try(fc.lock()) match { case Success(lock) => println("Is shared lock: " + lock.isShared) fc case Failure(ex) => Try(fc.close()) throw ex } } }