从一个文件到另一个文件的高效复制

时间:2009-07-15 20:09:36

标签: java concurrency copy io

我正在用Java构建一个系统,它必须将文件的一个子集复制到另一个文件中(不一定要复制到文件的开头)。即我有以下参数:

File srcFile, File dstFile, long srcFileOffset, long dstFileOffset, long length

多个线程可以从同一个源文件读取并同时写入同一目标文件(尽管具有不同的偏移量),因此我需要该进程是线程安全的(即防止其他线程在文件中搜索线程正在写/读。)

你会如何实现这个?我应该使用RandomAccessFile还是Java NIO?我需要什么样的锁才能获得?例如。 RandomAccessFile实例是否自动获取文件的系统范围锁定,还是需要单独保存?

编辑:看起来randomAccessFile.getChannel().tryLock()获取系统范围的锁,但它由VM保留,而不是调用线程。因此,如果我正在使用它,那么我也需要为该线程获取一个锁(或者实际上是两个,因为我需要锁定源文件和目标文件)。

2 个答案:

答案 0 :(得分:2)

我编写了一个小测试代码。似乎在WinXP上没有问题地工作:

import java.io.RandomAccessFile;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MultiRAF {
    public static void main(String[] args) throws Exception {
        RandomAccessFile raf = new RandomAccessFile("testraf.dat", "rw");
        raf.setLength(4096);
        raf.close();
        ExecutorService exec = Executors.newCachedThreadPool();
        for (int k = 0; k < 4; k++) {
            final int offset = k * 1024;
            final int kid = k;
            exec.submit(new Runnable() {
                public void run() {
                    try {
                        RandomAccessFile raf = new RandomAccessFile(
                            "testraf.dat", "rw");
                        for (int j = 0; j < 100; j++) {
                            System.out.printf("%d accessing%n", kid);
                            byte[] data = new byte[1024];
                            for (int i = 0; i < data.length; i++) {
                                data[i] = (byte)i;
                            }
                            raf.seek(offset);
                            raf.write(data);
                            System.out.printf("%d done%n", kid);
                        }
                        raf.close();
                    } catch (Exception ex) {
                        System.err.printf("%d failed%n", kid);
                        ex.printStackTrace();
                    }

                };
            });
        }
        exec.shutdown();
    }
}

答案 1 :(得分:1)

你可以在srcFile上打开一个FileInputStream,跳过(srcFileOffset),然后从那里读取。但是要在某个偏移处写入目标文件,您将需要RandomAccessFile。

对于锁定,您可以使用单例来读取/写入文件,并同步对象的读/写方法。