Какой метод более эффективен для объединения больших файлов в Java с помощью FileChannels - PullRequest
3 голосов
/ 20 мая 2011

Я хочу выяснить, какой из двух методов лучше всего подходит для объединения моих текстовых файлов на 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 Ответ

3 голосов
/ 20 мая 2011

TransferTo () может быть гораздо более эффективным, так как копирование данных происходит меньше, или его нет, если все это можно сделать в ядре. И если он не на вашей платформе, он все равно будет использовать сильно настроенный код.

Вам нужен цикл, однажды он будет повторяться, и ваш код продолжит работать.

...