Пишите большие файлы, используя класс RandomAccessFile - PullRequest
0 голосов
/ 01 февраля 2019

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

Чтение всего исходного файла, как показано ниже:

RandomAccessFile f = new RandomAccessFile(origin, "r");
originalBytes = new byte[(int) f.length()];
f.readFully(originalBytes);

А потом скопируйте все в контейнер следующим образом:

RandomAccessFile f2 = new RandomAccessFile(dest, "wr");
f2.seek(offset);
f2.write(originalBytes, 0, (int) originalBytes.length);

все в памяти, верно?Таким образом, копирование больших файлов может повлиять на память и привести к исключению OutOfMemory?

Лучше ли читать байты исходного файла байтами, а не целиком?В таком случае, как я должен действовать?Заранее спасибо.

РЕДАКТИРОВАТЬ:

После ответа mehdi maick Я наконец нашел решение: IЯ могу использовать RandomAccessFile в качестве места назначения, как я хотел, и поскольку у RandomAccessFile есть метод " getChannel ", который возвращает FileChannel, я могу передать это следующему методу, который будет делать копию (32 КБ за раз) файла впозиция пункта назначения, который я хочу:

     public static void copyFile(File sourceFile, FileChannel destination, int position) throws IOException {
            FileChannel source = null;
            try {
                source = new FileInputStream(sourceFile).getChannel();
                destination.position(position);
                int currentPosition=0;
                while (currentPosition < sourceFile.length())
                    currentPosition += source.transferTo(currentPosition, 32768, destination);
            } finally {
                if (source != null) {
                    source.close();
                }

            }
        }

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Попробуйте использовать async nio Channel


    public void copyFile(String src, String target) {
        final String fileName = getFileName(src);
        try (FileChannel from = (FileChannel.open(Paths.get(src), StandardOpenOption.READ));
                FileChannel to = (FileChannel.open(Paths.get(target + "/" + fileName), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE))) {
            transfer(from, to, 0l, from.size());
        }
    }

    private String getFileName(final String src) {
        File file = new File(src);
        if (file.isFile()) {
            return file.getName();
        } else {
            throw new RuntimeException("src is not a valid file");
        }
    }

    private void transfer(final FileChannel from, final FileChannel to, long position, long size) throws IOException {
        while (position < size) {
            position += from.transferTo(position, Constants.TRANSFER_MAX_SIZE, to);
        }
    }

Это создаст асинхронные каналы для чтения и записи и эффективно передаст данные от первого к последующему.

0 голосов
/ 01 февраля 2019

Чтение в блоках / блоках, например, 64 Кб за раз, используя FileInputStream и FileOutputStream.

Если вам нужно повысить производительность, вы можете попробовать использовать потоки, один поток для чтения и другой потокдля записи.

Вы также можете повысить производительность, используя прямые буферы NIO.
См., например, Простое правило, когда мне следует использовать прямые буферы с Java NIO для сетевого ввода-вывода?

...