【问题标题】:Efficient copy from one file to another从一个文件到另一个文件的高效复制
【发布时间】:2009-07-15 20:09:35
【问题描述】:

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

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

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

您将如何实现这一点?我应该使用 RandomAccessFile 还是 Java NIO?我需要获取什么样的锁?例如。 RandomAccessFile-instance 会自动获取文件的系统范围锁定还是我需要单独保留它?

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

【问题讨论】:

    标签: java concurrency copy io


    【解决方案1】:

    我编写了一个小测试代码。在 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();
        }
    }
    

    【讨论】:

    • 有趣,我猜 seek 设置的位置是 RandomAccessFile 实例的本地位置。我不知道您可以打开多个对同一个文件具有写访问权限的实例,并且仍然在描述符中保留不同的位置..
    【解决方案2】:

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

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

    【讨论】:

    • +1。或许,随机访问的精简也应该提高 IO 性能。
    • 谢谢,我会试试的。然后我只需要将读取的数据存储在某个中间缓冲区中,这样我就不会将其逐字节写入 RandomAccessFile。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-22
    相关资源
    最近更新 更多