Эффективное копирование из одного файла в другой
Я строю систему на Java, которая должна копировать подмножество файла в другой файл (не обязательно в начало файла). Т.е. у меня есть следующие параметры:
File srcFile, File dstFile, long srcFileOffset, long dstFileOffset, long length
Несколько потоков могут одновременно считывать из одного и того же исходного файла и записывать в один и тот же конечный файл (хотя и с разными смещениями), поэтому мне нужно, чтобы процесс был безопасным для потоков (то есть предотвращал поиск других потоков в файле, пока поток записи / чтения).
Как бы вы это реализовали? Должен ли я использовать RandomAccessFile или Java NIO? Какие замки мне нужно приобрести? Например, экземпляр RandomAccessFile автоматически получает общесистемную блокировку файла или мне нужно хранить ее отдельно?
Редактировать: выглядит как randomAccessFile.getChannel().tryLock()
получает блокировку всей системы, но она удерживается виртуальной машиной, а не вызывающим потоком. Так что, если я использую это, тогда мне нужно также получить блокировку для потока (или две на самом деле, так как мне нужно заблокировать как исходный, так и целевой файл).
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();
}
}
Вы можете просто открыть FileInputStream в srcFile, пропустить (srcFileOffset) и читать оттуда. Но для записи в целевой файл с определенным смещением вам понадобится RandomAccessFile.
Что касается блокировки, вы можете использовать синглтон для чтения / записи из файла и синхронизации методов чтения / записи на вашем объекте.