Какой метод более эффективен для объединения больших файлов в Java с помощью FileChannels
Я хочу выяснить, какой из двух методов лучше всего подходит для объединения моих текстовых файлов на Java. Если у кого-то есть понимание того, что он может рассказать о том, что происходит на уровне ядра, которое объясняет разницу между этими методами записи в FileChannel, я был бы очень признателен.
Из того, что я понимаю из документации и других разговоров о переполнении стека, allocateDirect выделяет пространство прямо на диске и в основном избегает использования оперативной памяти. У меня есть опасение, что ByteBuffer, созданный с помощью allocateDirect, может потенциально переполниться или не быть выделенным, если файл имеет большой размер, например, 1 ГБ. На этом этапе разработки нашего программного обеспечения я гарантирую, что размер файла не будет превышать 2 ГБ; но в будущем есть вероятность, что он может достигать 10 или 20 ГБ.
Я заметил, что цикл TransferFrom никогда не проходит цикл более одного раза... так что, похоже, он успешно записывает весь infile одновременно; но я не проверял его с файлами размером более 60 МБ. Я сделал петлю, хотя, потому что документация указывает, что нет никакой гарантии того, сколько будет написано сразу. Поскольку TransferFrom может принимать в моей системе только параметр int32 в качестве параметра подсчета, я не смогу указать, что за один раз будет передаваться более 2 ГБ... Опять же, опыт работы с ядром помог бы мне понять.
Заранее спасибо за помощь!!
Использование ByteBuffer:
boolean concatFiles(StringBuffer sb, File infile, File outfile) {
FileChannel inChan = null, outChan = null;
try {
ByteBuffer buff = ByteBuffer.allocateDirect((int)(infile.length() + sb.length()));
//write the stringBuffer so it goes in the output file first:
buff.put(sb.toString().getBytes());
//create the FileChannels:
inChan = new RandomAccessFile(infile, "r" ).getChannel();
outChan = new RandomAccessFile(outfile, "rw").getChannel();
//read the infile in to the buffer:
inChan.read(buff);
// prep the buffer:
buff.flip();
// write the buffer out to the file via the FileChannel:
outChan.write(buff);
inChan.close();
outChan.close();
} catch...etc
}
Использование trasferTo (или TransferFrom):
boolean concatFiles(StringBuffer sb, File infile, File outfile) {
FileChannel inChan = null, outChan = null;
try {
//write the stringBuffer so it goes in the output file first:
PrintWriter fw = new PrintWriter(outfile);
fw.write(sb.toString());
fw.flush();
fw.close();
// create the channels appropriate for appending:
outChan = new FileOutputStream(outfile, true).getChannel();
inChan = new RandomAccessFile(infile, "r").getChannel();
long startSize = outfile.length();
long inFileSize = infile.length();
long bytesWritten = 0;
//set the position where we should start appending the data:
outChan.position(startSize);
Byte startByte = outChan.position();
while(bytesWritten < length){
bytesWritten += outChan.transferFrom(inChan, startByte, (int) inFileSize);
startByte = bytesWritten + 1;
}
inChan.close();
outChan.close();
} catch ... etc
1 ответ
TransferTo() может быть гораздо более эффективным, так как копирование данных происходит меньше, или вообще без него, если все это можно сделать в ядре. И если он не на вашей платформе, он все равно будет использовать сильно настроенный код.
Вам нужен цикл, однажды он будет повторяться и ваш код продолжит работать.