Поток ввода читает данные из внешнего источника (файл, сеть, клавиатура и т.д.) в программу на Java.
InputStream – абстрактный базовый класс всех байтовых входных потоков (для чтения сырых бинарных данных).
Reader – абстрактный базовый класс всех символьных входных потоков (для чтения текстовых данных с учетом кодировки символов).
Примеры входных потоков: FileInputStream (чтение из файла), ByteArrayInputStream (чтение из массива байт в памяти), System.in (чтение с консоли, стандартный ввод).
Пояснение:
Потоки ввода используются, чтобы считать данные из различных источников во время выполнения программы. Java предоставляет множество классов ввода в пакете java.io. Все они делятся на байтовые (наследники InputStream) для чтения необработанных байтов и символьные (наследники Reader) для чтения текстовой информации (символов Unicode) с учетом кодировки. Когда мы читаем текстовые данные, обычно предпочитаем символьные потоки (например, FileReader или BufferedReader), чтобы Java сама преобразовывала байты в символы согласно заданной кодировке (по умолчанию UTF-8 или кодировка системы). Байтовые же потоки пригодятся для чтения бинарных файлов – например, изображений, аудио, видео, или любых данных, не являющихся простым текстом.
Класс InputStream определяет базовые методы для чтения байтов, главный из которых – int read(). Этот метод пытается прочитать один байт данных и возвращает его как число от 0 до 255 (тип int). Когда поток достигает конца данных (end-of-file), метод read() возвращает -1. Есть также перегруженные варианты read(byte[] buffer) для чтения сразу массива байтов. Поскольку InputStream – абстрактный, конкретные его подклассы реализуют чтение из разных источников. Например, FileInputStream открывает файл и читает байты из файла, ByteArrayInputStream читает из массива байтов, а System.in позволяет читать байты, вводимые пользователем в консоль.
Важно закрывать поток после завершения работы, чтобы освободить ресурсы (например, закрыть файл). Начиная с Java 7, для упрощения можно использовать конструкцию try-with-resources, благодаря тому что InputStream и Reader реализуют интерфейс AutoCloseable. Это гарантирует автоматическое закрытие потока даже при возникновении исключений.
Рассмотрим небольшой пример чтения данных из файла с использованием FileInputStream. В этом коде мы читаем содержимое файла по байтам и выводим числовое значение каждого байта:
import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;
try (InputStream input = new FileInputStream("example.bin")) {
int data;
while ((data = input.read()) != -1) { // читаем байт за байтом
System.out.println("Byte value: " + data); // выводим значение байта
}
} catch (IOException e) {
e.printStackTrace();
}
В этом примере с помощью input.read() читаются байты из файла example.bin до тех пор, пока метод не вернет -1, что означает конец файла. Мы выводим значение каждого прочитанного байта. В реальной ситуации вместо вывода можно обработать данные иначе – например, сохранить их, если это байты изображения, или преобразовать в символы. Если необходимо читать текстовый файл, то предпочтительнее воспользоваться символьным потоком. Например, можно обернуть FileInputStream в InputStreamReader, указав нужную кодировку, или сразу использовать FileReader (по умолчанию использует кодировку системы). Символьные потоки предоставляют методы удобного чтения, например read(char[] cbuf) или чтение строк через BufferedReader.readLine(). Ниже мы еще покажем пример с символьным потоком в контексте буферизации.
Обратите внимание, что блок try использует try-with-resources – это позволяет не вызывать явно input.close(). При выходе из блока try JVM автоматически вызовет close() на FileInputStream, освобождая системный ресурс (файл). Без этого файла могли бы остаться открытыми, что является плохой практикой. Современные Java-разработчики почти всегда используют try-with-resources для работы с потоками ввода/вывода, чтобы обезопасить код от утечек ресурсов.
