Почему метод read возвращает int java
Перейти к содержимому

Почему метод read возвращает int java

  • автор:

Класс InputStream

Базовый класс InputStream представляет классы, которые получают данные из различных источников:

  • массив байтов
  • строка (String)
  • файл
  • канал (pipe): данные помещаются с одного конца и извлекаются с другого
  • последовательность различных потоков, которые можно объединить в одном потоке
  • другие источники (например, подключение к интернету)

Для работы с указанными источниками используются подклассы базового класса InputStream:

BufferedInputStream Буферизированный входной поток ByteArrayInputStream Позволяет использовать буфер в памяти (массив байтов) в качестве источника данных для входного потока. DataInputStream Входной поток, включающий методы для чтения стандартных типов данных Java FileInputStream Для чтения информации из файла FilterInputStream Абстрактный класс, предоставляющий интерфейс для классов-надстроек, которые добавляют к существующим потокам полезные свойства. InputStream Абстрактный класс, описывающий поток ввода ObjectInputStream Входной поток для объектов StringBufferInputStream Превращает строку (String) во входной поток данных InputStream PipedInputStream Реализует понятие входного канала. PushbackInputStream Входной поток, поддерживающий однобайтовый возврат во входной поток SequenceInputStream Сливает два или более потока InputStream в единый поток

  • int available() — возвращает количество байтов ввода, доступные в данный момент для чтения
  • close() — закрывает источник ввода. Следующие попытки чтения передадут исключение IOException
  • void mark(int readlimit) — помещает метку в текущую точку входного потока, которая остаётся корректной до тех пор, пока не будет прочитано readlimint байт
  • boolean markSupported() — возвращает true, если методы mark() и reset() поддерживаются потоком
  • int read() — возвращает целочисленное представление следующего доступного байта в потоке. При достижении конца файла возвращается значение -1
  • int read(byte[] buffer) — пытается читать байты в буфер, возвращая количество прочитанных байтов. По достижении конца файла возвращает значение -1
  • int read(byte[] buffer, int byteOffset, int byteCount) — пытается читать до byteCount байт в buffer, начиная с смещения byteOffset. По достижении конца файла возвращает -1
  • reset() — сбрасывает входной указатель в ранее установленную метку
  • long skip(long byteCount) — пропускает byteCount байт ввода, возвращая количество проигнорированных байтов

Как преобразовать InputStream в строку

    Using IOUtils.toString (Apache Utils):

 String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8); 
 String result = CharStreams.toString(new InputStreamReader( inputStream, Charsets.UTF_8)); 
 Scanner s = new Scanner(inputStream).useDelimiter("\\A"); String result = s.hasNext() ? s.next() : ""; 
 String result = new BufferedReader(new InputStreamReader(inputStream)) .lines().collect(Collectors.joining("\n")); 
 String result = new BufferedReader(new InputStreamReader(inputStream)).lines() .parallel().collect(Collectors.joining("\n")); 
 final int bufferSize = 1024; final char[] buffer = new char[bufferSize]; final StringBuilder out = new StringBuilder(); Reader in = new InputStreamReader(inputStream, "UTF-8"); for (; ; ) < int rsz = in.read(buffer, 0, buffer.length); if (rsz < 0) break; out.append(buffer, 0, rsz); >return out.toString(); 
 StringWriter writer = new StringWriter(); IOUtils.copy(inputStream, writer, "UTF-8"); return writer.toString(); 
 ByteArrayOutputStream result = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) != -1) < result.write(buffer, 0, length); >return result.toString("UTF-8"); 
 String newLine = System.getProperty("line.separator"); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); StringBuilder result = new StringBuilder(); String line; boolean flag = false; while ((line = reader.readLine()) != null) < result.append(flag? newLine: "").append(line); flag = true; >return result.toString(); 
 BufferedInputStream bis = new BufferedInputStream(inputStream); ByteArrayOutputStream buf = new ByteArrayOutputStream(); int result = bis.read(); while(result != -1) < buf.write((byte) result); result = bis.read(); >return buf.toString(); 
 int ch; StringBuilder sb = new StringBuilder(); while((ch = inputStream.read()) != -1) sb.append((char)ch); reset(); return sb.toString(); 

BufferedInputStream

Буферизация ввода-вывода является удобным способом оптимизации производительности, позволяя заключить в оболочку любой поток класса InputStream. У класса есть конструктор, где размер буфера устанавливается по умолчанию. Также можно использовать конструктор, где размер буфера устанавливается вручную. Рекомендуется использовать размеры буфера, кратные размеру страницы памяти, дисковому блоку и т.п. и может зависеть от принимающей операционной системы, объёма доступной памяти и конфигурации машины.

ByteArrayInputStream

Класс ByteArrayInputStream использует байтовый массив в качестве источника данных. У данного класса можно не вызывать метод close().

DataInputStream — Форматированное чтение из памяти

Для чтения байтовых данных (не строк) применяется класс DataInputStream. В этом случае необходимо использовать классы из группы InputStream. Для преобразования строки в массив байтов, пригодный для помещения в поток ByteArrayInputStream, в классе String предусмотрен метод getBytes(). Полученный ByteArrayInputStream представляет собой поток InputStream, подходящий для передачи DataInputStream. При побайтовом чтении символов из форматированного потока DataInputStream методом readByte() любое полученное значение будет считаться действительным, поэтому возвращаемое значение неприменимо для идентификации конца потока. Вместо этого можно использовать метод available(), который сообщает, сколько еще осталось символов. Класс DataInputStream позволяет читать элементарные данные из потока через интерфейс DataInput, который определяет методы, преобразующие элементарные значения в форму последовательности байтов. Такие потоки облегчают сохранение в файле двоичных данных. Конструктор:

 DataInputStream(InputStream stream) 
  • readDouble()
  • readBoolean()
  • readInt()

FileInputStream

Класс FileInputStream создаёт объект класса InputStream, который можно использовать для чтения байтов из файла.

  • FileInputStream (File file) — указывается объекта типа File
  • FileInputStream (FileDescriptor fd)
  • FileInputStream (String path) — указывается полное имя файла

При создании объект открывается для чтения. Класс переопределяет методы класса InputStream, кроме методов mark() и reset().

Для чтения байтов входного потока из файла используется конструкция:

 File file = . InputStream in = null; try < in = new BufferedInputStream(new FileInputStream(file)); . finally < if (in != null) < in.close(); >> > 

PushbackInputStream

Разновидность буферизации, обеспечивающая чтение байта с последующим его возвратом в поток. Класс PushbackInputStream представляет механизм «заглянуть» во входной поток и увидеть, что оттуда поступит в следующий раз, не извлекая информации.

У класса есть дополнительный метод unread().

SequenceInputStream

Класс SequenceInputStream позволяет соединять вместе несколько экземпляров класса InputStream. Конструктор принимает в качестве аргумента либо пару объектов класса InputStream, либо интерфейс Enumeration.

Во время работы класс выполняет запросы на чтение из первого объекта класса InputStream и до конца, а затем переключается на второй. При использовании интерфейса работа продолжится по всем объектам класса InputStream. По достижении конца каждого файла, связанный с ним поток закрывается. Закрытие потока, созданного объектом класса SequenceInputStream, приводит к закрытию всех открытых потоков.

Как именно работает метод read() у InputStream?

В консоль выводится 253, а не -3.

Почему так происходит?

Тип данных int в Java является дополненнным до двух целым числом и использует 32 бита вместо 8.

В 32х битном виде число 253 будет:

00000000000000000000000011111101 

т. е. метод read() возвращает не само значение byte, а его представление в 32х битном виде.

Как хранятся значения в int в byte

| число | 32 bit | 8 bit | ----- -------------------------------- -------- | . . | . . . . . . . . . . . . . . . . | | . . | . . . . . . . . . . . . . . . . | | -128 | 11111111111111111111111110000000 | 10000000 | | -127 | 11111111111111111111111110000001 | 10000001 | | -126 | 11111111111111111111111110000010 | 10000010 | | -125 | 11111111111111111111111110000011 | 10000011 | | . . | . . . . . . . . . . . . . . . . | . . . . | | . . | . . . . . . . . . . . . . . . . | . . . . | | -2 | 11111111111111111111111111111110 | 11111110 | | -1 | 11111111111111111111111111111111 | 11111111 | | 0 | 00000000000000000000000000000000 | 00000000 | | 1 | 00000000000000000000000000000001 | 00000001 | | 2 | 00000000000000000000000000000010 | 00000010 | | . . | . . . . . . . . . . . . . . . . | . . . . | | . . | . . . . . . . . . . . . . . . . | . . . . | | 125 | 00000000000000000000000001111101 | 01111101 | | 126 | 00000000000000000000000001111110 | 01111110 | | 127 | 00000000000000000000000001111111 | 01111111 | | . . | . . . . . . . . . . . . . . . . | | . . | . . . . . . . . . . . . . . . . | 

Диапазон byte в Java лежит от -128 до 127, а возвращаемое значение метода read() лежит в диапазоне от 0 до 255.

Что происходит с числом byte в методе read

Чтобы получить представление byte в int в методе read() используется побитовое «И» c числом 255, т. е. убираем лидирующие единицы.

| число | 32 bit | ----- -------------------------------- | -3 | 11111111111111111111111111111101 | И | 255 | 00000000000000000000000011111111 | = | 253 | 00000000000000000000000011111101 | 

Чтобы из представления получить обратно значение byte в int, нужно выполнить обратную операцию побитовое «ИЛИ» c числом -256, т. е. добавляем лидирующие единицы.

| число | 32 bit | ----- -------------------------------- | 253 | 00000000000000000000000011111101 | ИЛИ | -256 | 11111111111111111111111100000000 | = | -3 | 11111111111111111111111111111101 | 

Что происходит с числом byte == -1 в методе read()

То же самое: убираем лидирующие единицы.

| число | 32 bit | ----- -------------------------------- | -1 | 11111111111111111111111111111111 | И | 255 | 00000000000000000000000011111111 | = | 255 | 00000000000000000000000011111111 | 

Отслеживать
ответ дан 16 июл 2019 в 11:11
user236980 user236980

Спасибо, классные ответы, но я несовсем разобрался. что будет если read прочтет -1 из потока? Он сделает побитовое И с 255, потом обратно ИЛИ с -256? Что в итоге? Получается int-овое представление будет совершенно другим? Как получить значение -1?

16 июл 2019 в 16:22

Если в методе read встречается byte со значением -1 то он вернет 255? В чем секрет? Как с этим работать?)

22 июл 2019 в 5:06

На все 4 вопроса вообще один ответ. Возвращается int потому что надо такой тип, который может вместить в себя один байт (реальные данные) плюс одно служебное значение (это тот самый -1 ), которое является признаком окончания чтения.

Вообще конечно можно бы было спроектировать метод read() так, чтобы он возвращал byte . Но тогда этот метод в случае окончания потока либо должен был бросать исключение, либо вводить допольнительный метод, при помощи которого бы можно было проверять окончание потока. С обоими способами бы были проблемы, т.к. с исключениями у программистов всегда бы оно ловилось, а природа исключений немного другая. А с дополнительным методом нельзя заставить обязать программиста его везде вызывать (ведь если этот вызов будет опущен, то как отделить, когда из потока методом read возращается 0 с данными от 0 когда данных нет.

Вообще говоря, этот метод редко используется, в основном из-за своих проблем с производительностью. Предпочтение отдаётся методу read(byte[]), который читает сразу массив байт.

P.S. Другой вопрос почему тут выбрали int , а не short . Точных причин сказать не могу, но скорее потому, что short считается неполноценным братом int . Многие арифметические алгоритмы предпочитают использовать всегда int , даже когда точно известно, что диапазона short вполне хватит. И ещё есть момент с short . JVM-инструкции более заточены на int , нежели на short .

Как работает метод read java

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

Синтаксис метода read() выглядит следующим образом:

public abstract int read() throws IOException 

Метод возвращает целое число int , которое представляет следующий байт в потоке. Если достигнут конец потока, то возвращается значение -1.

Пример использования метода read() :

try  // Создание объекта FileInputStream для чтения файла FileInputStream fis = new FileInputStream("example.txt"); // Чтение первого байта из файла int byteRead = fis.read(); // Пока не достигнут конец файла while (byteRead != -1)  // Обработка текущего байта System.out.print((char) byteRead); // Чтение следующего байта из файла byteRead = fis.read(); > // Закрытие потока ввода fis.close(); > catch (IOException e)  e.printStackTrace(); > 
  • создается объект FileInputStream , который открывает файл «example.txt» для чтения.
  • с помощью метода read() читается каждый байт из файла, пока не будет достигнут конец файла (-1)
  • прочитанные байты выводятся на экран в виде символов с помощью char
  • после окончания чтения файла, поток ввода закрывается методом close()

Важно отметить, что метод read() может выбрасывать исключение IOException , которое должно быть обработано с помощью блока try-catch или перенесено на уровень вызывающего кода с помощью оператора throws

Метод read()

Что делает метод read? Почему он возвращает int а не byte? Почему он не может возвращать byte?

* Reads the next byte of data from the input stream. The value byte is

* returned as an in the range to

* . If no byte is available because the end of the stream

* has been reached, the value is returned. This method

* blocks until input data is available, the end of the stream is detected,* or an exception is thrown.

Тип Int необходим для возможности выделять признак конца потока. Т.к. тип byte является знаковым, то его диапазон составляет [-128; 127], ([1000_0000; 0111_1111]), но если этот байт поместить в младший байт типа int, то диапазон значений становится [0; 255].

Что вернет метод read(), если он считывает файл и ему встречается байт равный -1?

-1 в типе int =
1111_1111__1111_1111__1111_1111__1111_1111
-1 в байте, помещенном в int =
0000_0000__0000_0000__0000_0000__1111_1111
или 255.

Перегрузки метода read() у inputStream

public abstract int read() throws IOException;

читает последовательно 1 байт из потока

public int read(byte b[]) throws IOException

читает из потока массив байт длинной b.length, либо меньше и сохраняет его в буферный массив b.
Возвращает количество реально переданных байт, либо -1 если поток закончился.

public int read(byte b[], int off, int len) throws IOException 

всё то же самое, что и предыдущий, только первый байт помещается в элемент массива b[off], следующий в b[off+1] и т.д.

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *