Русский English Тэги View Sergey Zolotaryov's profile on LinkedIn Вход
Сравнение производительности RandomAccessFile и FileChannel
Постоянная ссылка 10-05-2012 anydoby java

Сегодня был приятно удивлен тем, насколько можно увеличить производительность чтения файлов в Java, всего лишь написав небольшую обертку вокруг FileChannel.

Задача была поставлена такая: нужно в очень большом файле заменить строку с ошибочными данными на пробелы, не меняя размера файла. То есть найти строку с нужным номером, пропустив все остальные, и заменить ее на пустую.

Написал сначала с использованием RandomAccessFile в режиме "rw". Читаем строку, инкрементим номер, если наш, удаляем и выходим. На файле в 2гб удаление в середине файла занимало минут 5.

Начал копать, заменил readLine на свой skipLine, который не создает строку, а только пропускает байты. Результат примерно тот же.

Решил заменить RandomAccessFile на FileChannel. Открываем буфер и читаем. Никакой разницы. Почесал репу ещё немного, увеличил буфер до 10мб и файл прочитался за 2-3 секунды. Вот как выглядит это чудо:


    public class MappedFile
    {

        long pointer;

        long size;

        private final FileChannel channel;

        public MappedFile(FileChannel channel) throws IOException
        {
            size = channel.size();
            this.channel = channel;
            channel.position(0);
            createBuffer();
        }

        private void createBuffer() throws IOException
        {
            long bufferSize = bufferSize();
            buffer = channel.map(MapMode.READ_ONLY, pointer, bufferSize);
            buffer.load();
        }

        public void close() throws IOException
        {
            channel.close();
        }

        public long getFilePointer()
        {
            return pointer + buffer.position();
        }

        private long bufferSize()
        {
            long maximum = 10000000;
            if (maximum > size - pointer)
            {
                return size - pointer;
            }
            else
            {
                return maximum;
            }
        }

        public byte read() throws IOException
        {
            if (!buffer.hasRemaining())
            {
                pointer += buffer.limit();
                createBuffer();
            }
            return buffer.get();
        }

        public void seek(long cur) throws IOException
        {
            if (cur < pointer + buffer.capacity())
            {
                long newPosition = pointer - cur;
                buffer.position((int) newPosition);
            }
            else
            {
                pointer = cur;
                createBuffer();
            }
        }

        public boolean isAnythingLeftToRead()
        {
            return pointer < size;
        }

        MappedByteBuffer buffer;

    }

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

Добавить комментарий

Предыдущая статья Борьба с thread contention в XmlBeans