Почему чтение FileChannel никогда не заканчивается?

Когда я выполняю следующий класс

import java.io.*;
import java.nio.*;
import java.nio.file.*;
import java.nio.channels.*;

public class FileChannelTest {                                                                                                                      
    public static void main(final String... args) throws IOException {                                                                              
        final File file = File.createTempFile("temp", null);                                                                                        
        file.deleteOnExit();                                                                                                                        
        // write some                                                                                                                               
        try(OutputStream output = new FileOutputStream(file)) {                                                                                     
            output.write(new byte[128]);                                                                                                            
            output.flush();                                                                                                                         
        }                                                                                                                                           
        System.out.println("length: " + file.length());                                                                                             
        // read to end                                                                                                                              
        try(FileChannel channel                                                                                                                     
            = FileChannel.open(file.toPath(), StandardOpenOption.READ)) {                                                                           
            final ByteBuffer buffer = ByteBuffer.allocate(128);                                                                                     
            for(int read; (read = channel.read(buffer)) != -1; ) {                                                                                  
                System.out.println("read: " + read);                                                                                                
            }                                                                                                                                       
        }                                                                                                                                           
    }                                                                                                                                               
}

Цикл чтения никогда не заканчивается.

$ java -version
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)
$ java FileChannelTest.java
$ java FileChannelTest
length: 128
read: 128
read: 0
read: 0
read: 0
...
...
...

Файловый канал. read(ByteBuffer) говорит,

Считывает последовательность байтов из этого канала в заданный буфер. Байты считываются, начиная с текущей позиции файла этого канала, а затем позиция файла обновляется количеством фактически прочитанных байтов. В противном случае этот метод ведет себя точно так, как указано в интерфейсе ReadableByteChannel.

Что означает Иначе?


person Jin Kwon    schedule 15.01.2016    source источник
comment
В противном случае здесь используется значение во всех других отношениях, то есть единственное, что они задокументировали, это то, как оно отличается от ReadableByteChannel.read, а не все его поведение.   -  person Score_Under    schedule 15.01.2016
comment
Здесь есть два вопроса: (1) почему мой код ведет себя так, на что я ответил; (2) что означает «иначе», что едва ли заслуживает доверия.   -  person user207421    schedule 23.01.2016
comment
@EJP Я прикрепил второй вопрос о иначе, чтобы понять поведение FileChannel. Я мог бы сам погуглить, если бы захотел узнать, что означает слово иначе.   -  person Jin Kwon    schedule 24.01.2016


Ответы (2)


Когда вы читаете в ByteBuffer, он может прочитать только столько байтов, сколько доступно в буфере, т.е. byteBuffer.remaining() Это означает, что когда буфер заполнен, когда вы выполняете чтение, он возвращает 0.

Я предлагаю вам использовать либо clear(), если вы использовали все прочитанные данные, либо compact(), если вы использовали только часть прочитанных данных.

      for(int read; (read = channel.read(buffer)) != -1; ) {                                                                                  
            System.out.println("read: " + read);    
            buffer.clear(); // so we can read more data                                                                                           
      }   
person Peter Lawrey    schedule 15.01.2016

Ответ от @Peter Lawrey выше предлагает решение вашего бесконечного цикла. В дополнение к этому, чтобы ответить на ваш вопрос о том, что означает иначе в документации класса FileChannel, насколько я понимаю:

Из Документация по Java :

Считывает последовательность байтов из этого канала в заданный буфер. Байты считываются, начиная с текущей позиции файла этого канала, а затем позиция файла обновляется количеством фактически прочитанных байтов.

Этот метод будет вести себя точно так же, как метод ReadableByteChannel.read в режимах блокирующего и неблокирующего ввода-вывода, а также с точки зрения требований потокобезопасности. Единственная дополнительная операция, которую он выполняет (специализация чтения в терминологии ООП), заключается в том, что реализация FileChannel.read также увеличивает позицию в файле на количество байтов, фактически прочитанных из канала.

Надеюсь это поможет

person Prahalad Deshpande    schedule 15.01.2016
comment
Это неправильно. Он будет считывать байты в буфер, начиная с текущей позиции, ограниченной пределом, и соответствующим образом корректировать позицию. - person user207421; 23.01.2016
comment
@EJP Да, была опечатка - я использовал термин «начало буфера» в широком смысле. Отредактировал мой ответ. Спасибо!! - person Prahalad Deshpande; 23.01.2016
comment
Он не читает из буфера. Он читает в буфер. И он обновляет позицию buffer. Вам было бы намного лучше цитировать фактический Javadoc, чем постоянно коверкать его своими собственными неправильными словами. - person user207421; 23.01.2016
comment
Увеличьте позицию в файле с количеством прочитанных байтов, а не «до». Почему ты продолжаешь коверкать текст? - person user207421; 25.01.2016
comment
@EJP Обратите внимание, что это не намеренно. Я исправил рассматриваемое утверждение, но я думаю, что после цитирования документа Java любое дополнительное объяснение этого контекста будет понятно пользователю. На чем я сосредоточился, так это на объяснении того, что такое дополнительная операция, и значения слова иначе, поскольку в принятом ответе уже есть объяснение того, что делает метод. - person Prahalad Deshpande; 26.01.2016