почему буферы не были записаны в FileChannel - PullRequest
0 голосов
/ 01 сентября 2018

Сейчас я изучаю Java NIO, я нашел пример для объяснения операции сбора для FileChannel, как показано ниже:

public class ScattingAndGather {
    public static void main(String args[]) {
        gather();
    }

    public static void gather() {
        ByteBuffer header = ByteBuffer.allocate(10);
        ByteBuffer body = ByteBuffer.allocate(10);

        byte[] b1 = { '0', '1' };
        byte[] b2 = { '2', '3' };
        header.put(b1);
        body.put(b2);

        ByteBuffer[] buffs = { header, body };

        FileOutputStream os = null;
        FileChannel channel = null;
        try {
            os = new FileOutputStream("d:/scattingAndGather.txt");
            channel = os.getChannel();
            channel.write(buffs);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (channel != null) {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

хотя результат показывает, что файл создан, но он пустой, в нем должно быть 0123, что не так в этом примере?

1 Ответ

0 голосов
/ 01 сентября 2018

Проблема возникает из-за того, что вы никогда не сбрасываете позицию буфера.

Когда вы создаете оба ваших объекта ByteBuffer, они начинаются с нулевой позиции. Всякий раз, когда вы добавляете в них контент, их положение улучшается, что означает, что когда вы пытаетесь их записать, они сообщают о том, что больше нет байтов для чтения. Таким образом, перед выполнением любой такой операции вам необходимо как-то сбросить их положение.

Buffer предлагает несколько методов, наиболее простым из которых является flip(). Как вы можете видеть в документации здесь , используется следующее:

Переворачивает этот буфер. Ограничение устанавливается на текущую позицию, а затем позиция установлена ​​на ноль. Если знак определен, то он отбрасываются.

После последовательности операций чтения или вставки канала вызовите этот метод подготовить последовательность операций записи-записи канала или относительной операции get

Таким образом, прежде чем выписывать их, вам нужно перевернуть их. Кроме того, поскольку вы экспериментируете с java.nio, я не понимаю, почему вы не должны использовать операторы try with resources для управления различными ресурсами. Таким образом, вы избежите излишнего кода закрывания котельной пластины, который можно автоматически закрыть вручную.

Используя их, ваш код может значительно уменьшиться и стать более читабельным:

public static void gather() {
    ByteBuffer header = ByteBuffer.allocate(10);
    ByteBuffer body = ByteBuffer.allocate(10);

    byte[] b1 = { '0', '1' };
    byte[] b2 = { '2', '3' };
    header.put(b1);
    body.put(b2);

    //flip buffers before writing them out.
    header.flip();
    body.flip();
    ByteBuffer[] buffs = { header, body };

    try(FileOutputStream os = new  FileOutputStream("d:/scattingAndGather.txt");
 FileChannel channel = os.getChannel()) {
    channel.write(buffs);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
...