— Привет, Амиго! Сейчас я тебе расскажу про два интерфейса – InputStream и OutputStream. Объявлены они как абстрактные классы, но если начать разбираться, то можно увидеть, что по своей сути – это интерфейсы. Почти все их методы абстрактные, кроме нескольких незначительных методов. Очень похожи на нашего «телохранителя», которого мы рассматривали.
Это очень интересные интерфейсы. Пока что я специально буду называть их интерфейсы, чтобы ты понял, зачем они нужны. А потом мы поговорим, почему же их все-таки сделали абстрактными классами.
— Хорошо. Так что это за интерфейсы?
— Сейчас расскажу.
Есть такая интересная вещь в Java как «поток». Поток – это очень простая сущность. И его простота есть залог очень мощного механизма обмена данными. Потоки бывают двух видов: поток для чтения и поток для записи.
В поток для записи, как ты уже, наверное, догадался, можно записывать данные. Для этого у него есть метод write(). Из потока для чтения можно данные читать. Для этого у него есть метод read().
InputStream – это интерфейс потока чтения, описывающий такую способность: «из меня можно читать байты».
А OutputStream– это, соответственно, интерфейс потока записи, описывающий способность: «в меня можно записывать байты».
— И это все?
— Фактически да. Но все дело в том, что в Java есть очень много классов, которые умеют работать с интерфейсами InputStream и OutputStream. Например, ты хочешь прочитать файл с диска и вывести его содержимое на экран. Нет ничего проще.
Для того, чтобы прочитать данные из файла на диске, есть специальный класс FileInputStream, который реализует интерфейс InputStream. Хочешь записать прочитанные данные в другой файл? Для этого есть класс FileOutputStream, который реализует интерфейс OutputStream. Вот как выглядит код копирования [данных одного] файла в другой.
public static void main(String[] args) throws IOException
{
InputStream inStream = new FileInputStream("c:/source.txt");
OutputStream outStream = new FileOutputStream("c:/result.txt");
while (inStream.available() > 0)
{
int data = inStream.read(); //читаем один байт из потока для чтения
outStream.write(data); //записываем прочитанный байт в другой поток.
}
inStream.close(); //закрываем потоки
outStream.close();
}
Представь, что мы написали класс, и добавили ему способности InputStream и OutputStream.
Если мы корректно реализовали поддержку этих интерфейсов, то объекты нашего класса теперь можно сохранить в файл на диске. Просто вычитав их содержимое через метод read. Или загрузить из файла, создав объект и записав в него содержимое файла через метод write.
— А можно пример?
— Можно.
Код | Описание |
---|---|
|
Для простоты представим, что наш класс содержит в себе один объект – ArrayList типа Integer. Наполним список тестовыми данными. |
Теперь добавим в него методы read и write
Код | Описание |
---|---|
|
Теперь у нас в классе реализован метод read, который позволяет последовательно вычитать все содержимое нашего списка list.
И метод write, который позволяет записывать в наш list значения. |
Это, конечно, не реализация интерфейсов InputStream и OutputStream, но очень похоже.
— Да, это понятно. А как все-таки сохранить содержимое такого объекта в файл?
— Давай я напишу тебе пример:
public static void main(String[] args) throws IOException
{
MyClass myObject = new MyClass();
OutputStream outStream = new FileOutputStream ("c:/my-object-data.txt");
while (myObject.available() > 0)
{
int data = myObject.read(); //читаем один int из потока для чтения
outStream.write(data); //записываем прочитанный int в другой поток.
}
outStream.close();
}
public static void main(String[] args) throws IOException
{
InputStream inStream = new FileInputStream("c:/my-object-data.txt");
MyClass myObject = new MyClass();
while (inStream.available() > 0)
{
int data = inStream.read(); //читаем один int из потока для чтения
myObject.write(data); //записываем прочитанный int в другой поток.
}
inStream.close(); //закрываем потоки
}
— Ух ты! Действительно, очень похоже на работу с InputStream/OutputStream. Потоки – это крутая вещь!
— А то!