Не учить бессчетное количество — NIO в JAVA идет глубже

Java задняя часть

NIO в JAVA идет глубже

в предыдущей главеВвод/вывод и NIO в JAVAМы узнали, как использовать NIO, и давайте подробнее рассмотрим NIO.

Детали внутри буфера

BufferЗависит отданныеа такжеЧетыре индекса, которые могут эффективно обращаться к этим данным и манипулировать ими.сочинение. Четыре индекса

  • mark: пометка, так же как в игре установлен файл сохранения, его можно назватьreset()Метод возвращается в место, отмеченное меткой.
  • position: position, на самом деле буфер представляет собой украшенный массив, а данные чтения из канала помещаются в нижележащий массив. Так что это на самом деле как индекс. Таким образом, переменная position отслеживает, сколько данных было записано.
  • limit: предел, указывающий, сколько данных еще нужно извлечь или сколько места можно записать.
  • capacity: Емкость, указывающая максимальную емкость, которую можно сохранить в буфере.

Каждая операция чтения и записи в буфер изменяет состояние буфера, чтобы отразить это изменение. Записывая и отслеживая эти изменения, буфер может самостоятельно управлять своими ресурсами. Вот методы, используемые для установки и сброса индекса и запроса его значения индекса.

имя метода объяснять
capacity() Возвращает емкость буфера
clear() Очистите буфер, установите position на 0 и ограничьте установленную емкость. Вызовите этот метод, чтобы перезаписать буфер
flip() Установите ограничение на позицию и позицию на 0. Этот метод используется для подготовки к чтению уже записанных данных из буфера.
limit() возвращаемое предельное значение
limit(int lim) установить предельное значение
mark() установить Mac в положение
position() вернуть значение позиции
position(int pos) Установить ценность поста
remaining() Возвращает значение предельной позиции

Далее напишем пример для имитации изменения этих четырех индексов, например, есть строкаBuXueWuShu. Меняем местами соседние символы.

    private static void symmetricScranble(CharBuffer buffer){
        while (buffer.hasRemaining()){
            buffer.mark();
            char c1 = buffer.get();
            char c2 = buffer.get();
            buffer.reset();
            buffer.put(c2).put(c1);
        }
    }

    public static void main(String[] args) {
        char [] data = "BuXueWuShu".toCharArray();
        ByteBuffer byteBuffer = ByteBuffer.allocate(data.length*2);
        CharBuffer charBuffer = byteBuffer.asCharBuffer();
        charBuffer.put(data);
        System.out.println(charBuffer.rewind());
        symmetricScranble(charBuffer);
        System.out.println(charBuffer.rewind());
        symmetricScranble(charBuffer);
        System.out.println(charBuffer.rewind());
    }

rewind()метод заключается вpositionустановить на 0,markустановить на -1

просто входяsymmetricScranble ()Каждый индекс метода показан на следующем рисунке.

Потом первый звонокmark()тогда метод эквивалентен предоставлениюmarkПрисвоение эквивалентно установке точки возврата здесь. На данный момент индекс выглядит так

Тогда каждый раз, когда вы звонитеget()методPositionИндекс изменится, при первом вызове дваждыget()После метода каждый индекс выглядит следующим образом

а потом позвонилreset()другой методPosition=Mark, индекс в это время выглядит следующим образом

Тогда каждый раз, когда вы звонитеput()метод также изменитсяPositionзначение индекса,

Обратите внимание, что в этот момент первые два символа поменялись местами. Затем во втором раунде время снова начинает менятьсяMarkЗначение индекса, каждый индекс выглядит следующим образом

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

файл с отображением памяти

Файлы с отображением памяти — это не концепция, введенная в Java, а функция, предоставляемая операционной системой, которая поддерживается большинством операционных систем.

Файлы с отображением памяти позволяют нам создавать и изменять файлы, которые слишком велики для размещения в памяти. С файлом, отображаемым в память, мы можем предположить, что весь файл находится в памяти и к нему можно получить доступ целиком как к очень большому массиву. Таким образом, операция над файлом становится операцией над массивом байтов в памяти, а затем операция над массивом байтов будет сопоставлена ​​с файлом. Это сопоставление может отображать весь файл или только его часть. Когда операции над массивами байтов сопоставляются с файлами? Это определяется внутри операционной системы.

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

Как отображать файлы в память с помощью NIO? Вот небольшой пример, отображающий первые 1024 байта файла в память.

FileChannel fileChannel = new FileInputStream("").getChannel();
MappedByteBuffer map = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, 1024);

Чтобы создать файл с отображением памяти, просто вызовите каналmap()метод,MapModeЕсть следующие три параметра

  • READ_ONLY: создать файл карты только для чтения
  • READ_WRITE: создать файл карты, который можно читать и записывать.
  • PRIVATE: создать файл сопоставления с копированием при записи.

Мы можем просто сравнить использование отображаемых в памяти файлов с чтением и записью файлов с кешем.BufferСравнение скорости операций чтения и записи в файлы.

  public static void main(String[] args) throws IOException {
        String fileName="/Users/hupengfei/Downloads/a.sql";
        long t1=System.currentTimeMillis();
        FileChannel fileChannel = new RandomAccessFile(fileName,"rw").getChannel();
        IntBuffer map = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileChannel.size()).asIntBuffer();
        map.put(0);
        for (int i = 1; i < 50590; i++) {
            map.put(map.get(i-1));
        }
        fileChannel.close();
        long t=System.currentTimeMillis()-t1;
        System.out.println("Mapped Read/Write:"+t);

        long t2=System.currentTimeMillis();
        RandomAccessFile randomAccessFile = new RandomAccessFile(new File(fileName),"rw");
        randomAccessFile.writeInt(1);
        for (int i = 0 ; i<50590;i++){
            randomAccessFile.seek(randomAccessFile.length()-4);
            randomAccessFile.writeInt(randomAccessFile.readInt());
        }
        randomAccessFile.close();
        long t22=System.currentTimeMillis()-t2;
        System.out.println("Stream Read/Write:"+t22);
    }

нашел печать следующим образом

Mapped Read/Write:29
Stream Read/Write:2439

Чем больше файл, тем заметнее будет эта разница.

блокировка файла

Механизм блокировки файлов был представлен в JDK1.4, что позволяет нам синхронно обращаться к файлу как к общему ресурсу. Два потока, конкурирующие за один и тот же файл, могут исходить из разных операционных систем, разных процессов или одного и того же процесса, например, конкуренция двух потоков за файлы в Java. Блокировки файлов видны процессам других операционных систем, поскольку блокировка файлов напрямую связана с инструментом блокировки локальной операционной системы.

Ниже приведен простой пример блокировки файла.

    public static void main(String[] args) throws IOException, InterruptedException {
        FileOutputStream fileOutputStream = new FileOutputStream("/Users/hupengfei/Downloads/a.sql");
        FileLock fileLock = fileOutputStream.getChannel().tryLock();
        if (fileLock != null){
            System.out.println("Locked File");
            TimeUnit.MICROSECONDS.sleep(100);
            fileLock.release();
            System.out.println("Released Lock");
        }
        fileLock.close();
    }

через паруFileChannelперечислитьtryLock()илиlock()метод, вы можете получить FileLock всего файла

  • tryLock(): является неблокирующим, если блокировка не может быть получена, то он вернется непосредственно из вызова метода
  • lock(): блокирует, блокирует процесс до тех пор, пока не будет получена блокировка

перечислитьFileLock.release()Замок можно разблокировать.

Конечно, вы также можете заблокировать части файла следующими способами.

tryLock(long position,long size,boolean shared)
lock(long position,long size,boolean shared)

Для запертой области черезpositionа такжеsizeКвалифицированный, а третий параметр указывает, является ли блокировка общей. Метод блокировки без параметров блокирует весь файл, даже если файл становится больше. Если тип блокировки является эксклюзивной блокировкой, или общая блокировка может быть пройденаFileLock.isShared()сделать запрос.

Справочная статья