[英]Copying files with file locks in Java
我正在开发一个Java进程,它应该有效地(并递归地)将文件/目录从源位置复制到目标位置。
要做到这一点,我想:
为了检查内容是否相等,我计划使用Apache Commons IO FileUtils
方法contentsEqual(...)
。 要做到复制,我正打算使用Apache Commons IO FileUtils
方法copyFile(...)
所以,我提出的代码是(这只是为了文件,目录是递归处理到这个文件的方法):
private static void checkAndUpdateFile(File src, File dest) throws IOException {
FileOutputStream out = new FileOutputStream(dest);
FileChannel channel = out.getChannel();
FileLock lock = channel.lock();
if (!dest.exists()) {
FileUtils.copyFile(src, out);
} else if (!FileUtils.contentEquals(src, dest)) {
FileUtils.copyFile(src, out);
}
lock.release();
channel.close();
out.close();
}
这会锁定文件(很棒),并复制文件(超级)。
但是,无论何时复制文件,它都会将复制文件的上次修改时间戳设置为复制时间。 这意味着对FileUtils.contentEquals(src, dest)
后续调用继续返回false
,因此重新复制文件。
我真正喜欢的是类似于FileUtils.copyFile(src, dest, true)
,它保留了文件的时间戳 - 并且通过调用FileUtils.contentEquals(src, dest)
。 这将要求锁定在File
,而不是FileOutputStream
,否则对FileUtils.copyFile(src, dest, true)
的调用将失败并抛出异常,因为文件已被锁定。
或者,我考虑使用FileUtils.copyFile(src, dest, true)
方法执行的操作,即调用dest.setLastModified(src.lastModified())
。 但是,必须在释放锁之后调用此方法,如果同时执行多个相同的进程,则可能会导致问题。
我还考虑了将锁定放在源文件上的想法,但这没有用,因为我必须将它放在FileInputStream
,并且我想将File
传递给FileUtils.copyFile(src, dest)
。
所以:
copyFile(...)
) 您可以使用Guava Google Core Library
来比较两个文件。
ByteSource inByte = Resources.asByteSource(srcFileURL);
ByteSource outByte = Files.asByteSource(srcFileURL2);
boolean fileEquals= inByte.contentEquals(outByte));
所以...最后,我选择编写自己的copy()
和compare()
方法来使用已锁定的FileChannel
对象。 以下是我提出的解决方案 - 尽管我希望其他人可以提出改进建议。 这是通过查看apache.commons.io类的源代码通知FileUtils
和IOUtils
。
private static final int s_eof = -1;
private static final int s_byteBuffer = 10240;
private static void checkAndUpdateFile(File src, File dest) throws IOException {
FileInputStream in = new FileInputStream(src);
FileChannel srcChannel = in.getChannel();
FileChannel destChannel = null;
FileLock destLock = null;
try {
if (!dest.exists()) {
final RandomAccessFile destFile = new RandomAccessFile(dest, "rw");
destChannel = destFile.getChannel();
destLock = destChannel.lock();
copyFileChannels(srcChannel, destChannel);
dest.setLastModified(src.lastModified());
} else {
final RandomAccessFile destFile = new RandomAccessFile(dest, "rw");
destChannel = destFile.getChannel();
destLock = destChannel.lock();
if (!compareFileChannels(srcChannel, destChannel)) {
copyFileChannels(srcChannel, destChannel);
dest.setLastModified(src.lastModified());
}
}
} finally {
if (destLock != null) {
destLock.release();
}
if (destChannel != null) {
destChannel.close();
}
srcChannel.close();
in.close();
}
}
protected static void copyFileChannels(FileChannel src,
FileChannel dest) throws IOException {
final long size = src.size();
for (long pos = 0; pos < size; ) {
long count =
((size - pos) > s_byteBuffer) ? s_byteBuffer : (size - pos);
pos += dest.transferFrom(src, pos, count);
}
}
protected static boolean compareFileChannels(FileChannel a,
FileChannel b) throws IOException {
if (a.size() != b.size()) {
return false;
} else {
final ByteBuffer aBuffer = ByteBuffer.allocate(s_byteBuffer);
final ByteBuffer bBuffer = ByteBuffer.allocate(s_byteBuffer);
for (int aCh = a.read(aBuffer); s_eof != aCh; ) {
int bCh = b.read(bBuffer);
if (aCh != bCh || aBuffer.compareTo(bBuffer) != 0) {
return false;
}
aBuffer.clear();
aCh = a.read(aBuffer);
bBuffer.clear();
}
return s_eof == b.read(bBuffer);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.