Java - How to Lock Files Using File Channel (Java I/O Part 1)

By @murez-nst1/16/2018utopian-io

c82-java-fund-logo.jpg
Source: https://academy.oracle.com/en/oa-assets/i/c82/c82-java-fund-logo.jpg

What Will I Learn?

In this tutorial, I will guide you how to lock files by using File Channel while other processes will be blocked from attempting to gain access to the same file until the current process releases the lock. But, before we go any further, we need to grasp the fundamentals of reading from or writing to the stream based on the Java™ platform. A stream can represent many different kinds of sources and targets, including files, devices, memory or others.

  • Java™ I/O Stream
  • Java™ File Channel

Requirements


Difficulty

  • Basic

Tutorial Contents

  • Byte Streams

    The Byte stream is the lowest layer and the most primitive of Java I/O to perform any operation against a bytes of 8 bits. Next, all the types of streams that we will learn are built on byte stream, and the abstract class of InputStream and OutputStream is the superclass of all classes representing an input/ouput stream of bytes. This is the complete hierarchy:
    public abstract class java.io.InputStream
    extends java.lang.Object
    implements java.io.Closeable

    Example
    Read file: D:/Test.txt, then print its content on Console stream.


    import java.io.FileInputStream;
    import java.io.IOException;


    public class Main {
    public static void main(String[] args) {
    FileInputStream in = null;
    String plain = "";
    try {
    in = new FileInputStream("D:/Test.txt");
    byte[] bytes = new byte[5];
    int i, n = bytes.length;
    while(in.read(bytes) > 0) {
    plain += new String(bytes);
    for(i = -1; ++i < n; bytes[i] = 0);
    }
    } catch(IOException e1) {
    if(in != null)
    try { in.close(); }
    catch(IOException e2) { e2.printStackTrace(); }
    }
    System.out.println(plain);
    }
    }

    Always Close Streams!
    It is very important to close all streams, optionally inside the finally block to guarantee that they will be closed even if an error occurs. That practice helps us avoid serious resource leaks.

    Input
    Untitled 007.png

    Output
    Untitled 008.png

    References
    Java Official - https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html
    Android Official - https://developer.android.com/reference/java/io/InputStream.html



    `public` `abstract` `class` `java.io.`**`OutputStream`** `extends` `java.lang.`**`Object`** `implements` `java.io.`**`Closeable`**, `java.io.`**`Flushable`** - [`ByteArrayOutputStream`](https://docs.oracle.com/javase/8/docs/api/java/io/ByteArrayOutputStream.html) - [`FileOutputStream`](https://docs.oracle.com/javase/8/docs/api/java/io/FileOutputStream.html) - [`FilterOutputStream`](https://docs.oracle.com/javase/8/docs/api/java/io/FilterOutputStream.html) - [`ObjectOutputStream`](https://docs.oracle.com/javase/8/docs/api/java/io/ObjectOutputStream.html) - [`OutputStream`](https://docs.oracle.com/javase/8/docs/api/org/omg/CORBA/portable/OutputStream.html) - [`PipedOutputStream`](https://docs.oracle.com/javase/8/docs/api/java/io/PipedOutputStream.html) **Example** Write file to `D:/out/Test.txt` from local variable.
       
     import java.io.FileOutputStream;
     import java.io.IOException;
     
    public class Main { public static void main(String[] args) { String message = "Murez Nasution" + System.lineSeparator() + "Hello, world!"; /** * The try-with-resources Statement */ try(FileOutputStream out = new FileOutputStream("D:/out/Test.txt")) { out.write(message.getBytes()); } catch(IOException e) { e.printStackTrace(); } System.out.println("Successful"); } }

    The try-with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.lang.AutoCloseable, which includes all objects which implement java.io.Closeable, can be used as a resource.

    Output
    Untitled 009.png

    References
    Java Official:
    https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html
    https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
    Android Official - https://developer.android.com/reference/java/io/OutputStream.html


  • Character Streams
    The character stream uses and often as wrappers for the byte stream to perform the physical I/O, while the character stream handles translation between characters and bytes. All character stream classes are descended from abstract classes Reader and Writer. And here's the hierarchy:
    public abstract class java.io.Reader
    extends java.lang.Object
    implements java.io.Closeable, java.lang.Readable

    References
    Java Official:
    https://docs.oracle.com/javase/8/docs/api/java/io/Reader.html
    https://docs.oracle.com/javase/tutorial/essential/io/charstreams.html
    Android Official - https://developer.android.com/reference/java/io/Reader.html



    `public` `abstract` `class` `java.io.`**`Writer`** `extends` `java.lang.`**`Object`** `implements` `java.io.`**`Closeable`**, `java.io.`**`Flushable`**, `java.lang.`**`Appendable`** - [`BufferedWriter`](https://docs.oracle.com/javase/8/docs/api/java/io/BufferedWriter.html) - [`CharArrayWriter`](https://docs.oracle.com/javase/8/docs/api/java/io/CharArrayWriter.html) - [`FilterWriter`](https://docs.oracle.com/javase/8/docs/api/java/io/FilterWriter.html) - [`OutputStreamWriter`](https://docs.oracle.com/javase/8/docs/api/java/io/OutputStreamWriter.html) - [`PipedWriter`](https://docs.oracle.com/javase/8/docs/api/java/io/PipedWriter.html) - [`PrintWriter`](https://docs.oracle.com/javase/8/docs/api/java/io/PrintWriter.html) - [`StringWriter`](https://docs.oracle.com/javase/8/docs/api/java/io/StringWriter.html) **References** **Java Official** - [https://docs.oracle.com/javase/8/docs/api/java/io/Writer.html](https://docs.oracle.com/javase/8/docs/api/java/io/Writer.html) **Android Official** - [https://developer.android.com/reference/java/io/Writer.html](https://developer.android.com/reference/java/io/Writer.html) **Example** Now, we'll try to scan what you type in Console stream, then save them to the array of `String`. But, when user enters the `stop` word exactly, the current scan will stop immediately. Next, the all of lines that saved in the memory will print out to the file: `D:/Test.txt`.
       
     import java.io.BufferedReader;
     import java.io.BufferedWriter;
     import java.io.FileWriter;
     import java.io.IOException;
     import java.io.InputStreamReader;
     
    public class Main { public static void main(String[] args) { System.out.println("Enter lines:"); final int N = 5; String[] lines = new String[N]; /** * Scan lines from Console */ try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) { for(int i = 0; i < N; i++) { if((lines[i] = reader.readLine()).equals("stop")) break; } } catch(IOException e) { e.printStackTrace(); } /** * Print all of lines */ try(BufferedWriter writer = new BufferedWriter(new FileWriter("D:/Test.txt"))) { int i = 0; String line; if((line = lines[i]) != null) writer.write(line); while(++i < N) if((line = lines[i]) != null) writer.write(System.lineSeparator() + line); } catch(IOException e) { e.printStackTrace(); } } }

    Input
    Untitled 010.png
    Output
    Untitled 011.png


  • File Channel

    And finally the time has come for us to implement file locking using File Channel. And here's the source codes.

       
     import java.io.BufferedReader;
     import java.io.IOException;
     import java.io.InputStreamReader;
     import java.io.RandomAccessFile;
     import java.nio.ByteBuffer;
     import java.nio.channels.FileChannel;
     import java.nio.channels.FileLock;
     import java.util.List;
     
    public class Main { public static void main(String[] args) { try(RandomAccessFile r = new RandomAccessFile("D:/Lock.txt", "rw"); FileChannel fc = r.getChannel()) { /** * Lock file */ FileLock lock = fc.tryLock(); System.out.println("Locking file was successful"); System.out.println("Enter lines (to stop, type: \"stop\"):"); String line; List lines = new java.util.ArrayList<>(); try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) { while(!(line = reader.readLine()).equals("stop")) lines.add(line); } int i = 0, n; ByteBuffer buffer; buffer = ByteBuffer.wrap(lines.get(i).getBytes()); fc.write(buffer); for(n = lines.size(); ++i < n; ) { buffer = ByteBuffer.wrap((System.lineSeparator() + lines.get(i)).getBytes()); fc.write(buffer); } /** * You do not have to declare this, * because we already use try-with-resources which will close `lock` automatically. */ //lock.release(); } catch(IOException e) { e.printStackTrace(); } } }

    Testing

    We'll try a simple test by creating a new file, i.e.: D:/Lock.txt and the whole contents come from the Console stream. The file will remain locked until the user has finished modifying the file.

    Untitled 012.png

    While we're typing and not trying to interrupt by giving the stop word, the file: D:/Lock.txt will not be able to be changed by anyone. And you will get a message like in the picture below (running on Windows platform).

    Untitled 013.png

    Then when you release the lock (of course, by giving the input stop), then another process that is accessing the same file has been able to change the contents of the file.
    Congratulations! We have successfully locked the file by using File Channel.


Thank you!

Share with heart



Posted on Utopian.io - Rewarding Open Source Contributors

7

comments