今天coding,有一个需求是在使用一个文件之前,要确认该文件是不是正在被写。调研了一下,有一些方案,有一些争论,在此处总结一下。 不过,还是觉得这其中没有一个特别让人舒服的方式。另外,文章最后给出了两个测试用到的类FileStatusTester和类FileOperator的链接。

##尝试一###

使用File类的canWrite()方法,测试结果是没有任何作用,无论文件处于什么状态,canWrite()方法都返回true,因为此方法是用于判定当前用户是否 有该文件的写权限,而不是判定文件当前是否可写。测试代码片段如下:

public void testCanWrite(File f) throws InterruptedException {
	while (true) {
		System.out.println(f.canWrite());
		Thread.sleep(5 * 1000);
	}
}

##尝试二###

使用File类的renameTo()方法,测试结果是无论现在文件正在被读还是被写,rename都会失败,说明这种方式可以。测试代码片段如下:

public void testRename(File f) throws InterruptedException {
	//只要文件在被写或者被读,就不能rename
	File file = new File("watchedDir/2.txt");
	while (true) {
		System.out.println(f.renameTo(f));
		Thread.sleep(5 * 1000);
	}
}

但是,renameTo()方法是在很多方面都是平台相关的:在某一个文件系统有效(如windows),可能在另一个文件系统(如linux)就是无效的;该方法可能不是原子操作; 如果重命名的目标文件的路径已经存在,该方法也可能会失败。所以,renameTo()方法并不是一个可靠的方式。即使上述可能性都不会发生,如果 重命名成功,还要再重命名为原来的文件名。

##尝试三###

使用FileLock的tryLock()方法,测试结果是如果该文件已经被别的进程或线程加锁使用,tryLock()方法就会返回空值,说明该方法在文件正在加锁被写的情况 下可用于判断文件是否正在被写,但是,如果文件正在被写,且没有加锁,那么tryLock()就能获得该文件的锁,不能正确判定文件状态了。测试代码片段如下:

public void testFileLock(File f) throws FileNotFoundException, IOException, InterruptedException {
	//只要该文件加了文件锁,此种方法才能有效;如果该文件正在被写且没有加文件锁,或者正在被读,此处仍能获得
	//该文件的文件锁,此时通过此种方法判断文件是否在使用中是无效的
	while (true) {
		// get the file lock
		try (RandomAccessFile randFile = new RandomAccessFile(f, "rw")){
			FileChannel channel = randFile.getChannel();
			FileLock lock = channel.tryLock();

			if (lock != null) {
				lock.release();
				System.out.println("true");
			}
			else System.out.println("false");
			
			Thread.sleep(5 * 1000);
		} 
	}
}

上述方式也只是在windows下可用,在unix系统下,无任何作用。

##尝试四###

有人提出使用File的lastModified()方法给出的是文件最后一次修改时间,但是经过测试该时间是开始修改文件的时间,而不是修改文件完毕的时间,所以不能知晓文件 是否正在被写。

为什么没有一个合适的接口?或者是我没有找到,持续寻找ing…

类FileStatusTester

类FileOperator