在对文件操作过程中,有时候需要对文件进行加锁操作,防止其他线程访问该文件。在NIO中提供了文件锁的功能,当一个线程文件锁定后,其他的线程是无法操作此文件的, 要想进行文件锁定的操作,则要使用FileLock类完成, 此类的对象需要依靠 FileChannel 进行实例化。
在NIO未出现之前,加锁文件可以使用RandomAccessFile类操作文件。在java.io.RandomAccessFile类的open方法,提供了参数实现独占的方式打开文件:
RandomAccessFile raf = new RandomAccessFile(file, "rws"); |
其中的“rws”参数,rw代表读取和写入,s代表了同步方式,也就是同步锁。这种方式打开的文件,就是独占方式的。
在NIO中,可以用FileChannel实例化文件锁FileLock对象的方法,加锁方法为:
RandomAccessFile raf = new RandomAccessFile("file.txt", "rw"); FileChannel fc = raf.getChannel(); FileLock fl = fc.tryLock(); if(fl.isValid()) System.out.println("文件已被锁定."); |
下面就是一个文件加锁的例子,代码如下:
package com.javapp.ch10; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; public class FilelockTest { public static void main(String[] args) throws IOException, InterruptedException { File file = new File("D:\\test.txt"); RandomAccessFile raf = new RandomAccessFile(file, "rw"); FileChannel channel = raf.getChannel(); java.nio.channels.FileLock lock = channel.tryLock(); // 锁定60秒 Thread.sleep(60 * 1000); // 释放 lock.release(); // close channel.close(); raf.close(); } } |
上面程序以独占锁的方式只允许一个线程进行文件的读/写操作,将D盘目录下的 test.txt文件锁定60秒,如果D盘目录下没有test.txt文件,可以手动创建test.txt文件。
接下来编写一个测试一个读取锁定文件的程序,代码如下:
package com.javapp.ch10; import java.io.*; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.ByteBuffer; public class ReadFileTest { public static void main(String[] args) throws Exception{ File file = new File("D:\\test.txt"); FileInputStream ins = new FileInputStream(file); FileChannel fIns = ins.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(1024); while (true) { buffer.clear(); int r = fIns.read(buffer); if(r == -1){ break; } buffer.flip(); out(buffer); } } public static void out(ByteBuffer buffer){ for (int i = 0; i < buffer.limit(); i++) { System.out.print(buffer.get()); } } |
先运行FilelockTest类,锁定文件,然后执行ReadFileTest类,程序运行结果如下:
Exception in thread "main" java.io.IOException: 另一个程序已锁定文件的一部分,进程无法访问。 at sun.nio.ch.FileDispatcherImpl.read0(Native Method) at sun.nio.ch.FileDispatcherImpl.read(Unknown Source) at sun.nio.ch.IOUtil.readIntoNativeBuffer(Unknown Source) at sun.nio.ch.IOUtil.read(Unknown Source) at sun.nio.ch.FileChannelImpl.read(Unknown Source) at com.javapp.ch10.ReadFileTest.main(ReadFileTest.java:14) |