Java чтение/запись конструкции

Может кто-нибудь объяснить мне, почему эта конструкция не будет работать:

while (fileInputStream.available()>0) {    
    fileOutputStream.write(fileInputStream.read());
}

и этот работает просто отлично:

while (fileInputStream.available()>0) {
    int data = fileInputStream.read();
    fileOutputStream.write(data);
}

Как по мне, они идентичны, но 1-й не будет правильно записывать данные (запишет половину длины файла/данные).


person Hikaru    schedule 06.10.2015    source источник
comment
Есть ли петля, которую вы нам не показываете? Потому что read() читает только сегмент данных. Вообще говоря, этот сегмент определяется контейнером, а целое число составляет 32 бита, где поток вывода файлов принимает переменное количество байтов.   -  person Ya Wang    schedule 06.10.2015
comment
Они одинаковые. Обратите внимание, что это не копирует все содержимое входного потока в выходной поток. Он будет читать и записывать только один байт.   -  person Jesper    schedule 06.10.2015
comment
если вы хотите, чтобы это работало, вы должны ввести байтовый буфер docs.oracle.com/javase/7/docs/api/java/io/   -  person Ya Wang    schedule 06.10.2015
comment
Не используйте fileInputStream.available() для чтения цикла. Он не делает того, что вы думаете. Он просто сообщает вам, сколько байтов доступно без блокировки, что не обязательно является длиной файла. Это может повлиять на ваши результаты независимо от проблемы с переменной.   -  person RealSkeptic    schedule 06.10.2015


Ответы (3)


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

Хороший вопрос о переполнении стека о available()

JavaDoc доступен()


Правильный способ проверить, достигли ли вы EOF, состоит в том, чтобы убедиться, что read() вернул -1:

int data = fileInputStream.read();
while (data != -1) {
    fileOutputStream.write(data);
    data = fileInputStream.read();
}

Этот метод, вероятно, будет довольно медленным, если вы попытаетесь прочитать большие объемы данных. Вы можете ускорить это, прочитав больше байтов, используя метод read(byte[] b, int off, int len). Петля будет очень похожа на другую.

byte [] buffer = new byte[1024]; // 1kb buffer
int numBytesRead = fileInputStream.read(buffer);
while (numBytesRead != -1) {
    fileOutputStream.write(buffer, 0, numBytesRead);
    numBytesRead = fileInputStream.read(buffer);
}
person ug_    schedule 06.10.2015

Мой интерес пробудился, я написал этот небольшой тест:

public static void main(String[] args) throws IOException {

    FileInputStream fileInputStream = new FileInputStream("/home/nick/foo");
    FileOutputStream fileOutputStream = new FileOutputStream("/home/nick/bar");
    fileOutputStream.write(fileInputStream.read());

    fileOutputStream.flush();
    fileOutputStream.close();
    fileInputStream.close();
}

Это сработало, как и ожидалось - прочитал один байт из /home/nick/foo и записал его в /home/nick/bar

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

Обновленная программа:

public static void main(String[] args) throws IOException {

    FileInputStream fileInputStream = new FileInputStream("/home/nick/foo");
    FileOutputStream fileOutputStream = new FileOutputStream("/home/nick/bar");
    while (fileInputStream.available()>0) {    
        fileOutputStream.write(fileInputStream.read());
    }

    fileOutputStream.flush();
    fileOutputStream.close();
    fileInputStream.close();
}

Скопировал весь файл. (примечание: я бы не рекомендовал копировать файл побайтно, используйте классы буферизованного ввода-вывода для копирования целых фрагментов)

Вы случайно не забыли flush() и close() в OutputStream?

person NickJ    schedule 06.10.2015
comment
Я обновил первый пост - в этом вопросе цикл не имеет значения. Есть петля и есть разница - person Hikaru; 06.10.2015
comment
Проверил: да, файл копируется и некоторые данные из него можно прочитать, но содержимое явно повреждено. - person Hikaru; 06.10.2015
comment
Я закрыл его, но не смыл. Он работает с флеш(). Можете ли вы объяснить, почему? Согласно javadoc, метод flush для OutputStream ничего не делает. - person Hikaru; 06.10.2015
comment
Можете ли вы объяснить, почему? : честный ответ: нет. - person NickJ; 06.10.2015

Похоже, ваш цикл while выполняет предполагаемые вещи и пропускает то тут, то там.

public int available() throws IOException {
        return 0;
    }

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

См. здесь

person Murat Karagöz    schedule 06.10.2015
comment
Спасибо, мне кажется, это то, что происходит здесь. - person Hikaru; 06.10.2015