Главная » Статьи » Java » Java Ranger Basic

День 8/21
Java IO - Streams, Readers

Streams
Идея потоков в том, что у нас есть какой-то источник и какой-то приемник, и мы хотим пересылать байты. Эти оба устройства могут быть программными (из веба в файл), а могут быть аппаратными (веб-камера).
В streams все отрицательные числа и числа больше 255 считаются некорректными. Метод read() возвращает либо число от 0 до 255 – тогда это наши данные, либо число –1 – это означает, что данных больше нет. Все остальные числа он не должен возвращать, иначе – проблема с InputStream в данной JDK.
Когда мы работаем с устройствами ввода-вывода, часто появляется такой эффект, как буферизация – метод организации обмена ввода и вывода данных, который подразумевает использование буфера для временного хранения данных. При вводе данных одни процессы производят запись данных в буфер, а другие – чтение из него, при выводе – наоборот.

InputStream / OutputStream

InputStream и OutputStream – базовые абстрактные классы, задающие используемую модель входных и выходных потоков (это могут быть потоки данных из файла, веб-страницы, массивы байт, строки, данные с веб-камеры). У них основные методы – read(byte) и write(byte).

Reader / Writer

Reader и Writer – это абстрактные классы, управляющие потоками символов Unicode. У них основные методы – read(char) и write(char) – они работают с массивами char. Преобразование потока char в поток byte или наоборот – нетривиально, потому что и byte, и char здесь – codeunits. Из последовательности char, используя кодировку UTF-16, декодируются в массив int (это массив codepoints – номера символов в Unicode), потом применяется другая кодировка и преобразуется в массив байт – byte.

Чтобы записать строку в файл:

public static void main(String args) throws IOException {
String str = "Hello!";
try (OutputStream dst = new FileOutputStream(new File("d:/tmp.txt"))) {
Writer writer = new OutputStreamWriter(dst, "UTF-8");
writer.write(str);
writer.flush();
}
}

Здесь у нас напрямую класс java.io.File превращен в OutputStream с помощью класса-адаптера FileOutputStream. Но нам хорошо бы быть в блоке Reader/Writer. Если бы у нас был Writer, то мы бы использовали метод write(), где есть не только массив символов (уже неплохо), но и StringWriter прямо для строки. И нам теперь нужно тип OutputStream перегнать в Writer. Для этого нам нужен будет адаптер OutputStreamWriter.
Но это плохая стратегия, потому что в данном случае будет взята кодировка по умолчанию (UTF-8). А OutputStreamWriter будет поглощать строки и массивы char, а в OuputStream dst отдавать массивы байт byte. В целом это нехороший стиль кодирования. Лучше явно прописать, потому что эти параметры по умолчанию JVM можно переписывать с помощью флагов. И если у кого-то будет кодировка по умолчанию например, Latin-1, то наш Writer будет работать по-другому. Желательно никогда не опираться на дефолтные значения.
Нужно четко понимать, что расширение файла здесь не имеет значения, это просто часть имени, оно нужно только для ОС для определения типа файла, на внутренние байты это никак не влияет. То есть сохранять строку с текстом в файл с расширением txt – логично на человеческом уровне.

Строку удобно записывать с помощью Writer, массив байт – с помощью OutputStream, массив float – с помощью DataOutput (потому что у интерфейса DataOutput есть методы writeDouble(), writeFloat()).

ObjectInput / ObjectOutput

Есть еще пара интерфейсов – ObjectInput и ObjectOutput. У ObjectOutput есть удобный метод writeObject(Object), у которого в сигнатуре Object – то есть потенциально любой объект в Java можно записать куда угодно. При этом нельзя напрямую записать его в файл, у нас нет адаптера, который бы напрямую делал из файла ObjectOutput, но есть последовательность адаптеров – класс ObjectOutputStream в конструкторе получает OutputStream, а сам является ObjectOutput. То есть он удобен, у него есть метод writeObject(), а ему в аргументе нужен OutputStream. Мы ему в аргумент можем дать другой адаптер – FileOutputStream, который в конструктор себе получает имя файла или java.io.File, а сам является OutputStream.
Получается, мы берем два класса ObjectOutputStream и FileOutputStream, сращиваем их и получаем мост, с одного конца которого будет метод writeObject(Object), а с другого – файл, куда будут попадать данные.

Adapter / Decorator

Есть такое понятие – шаблоны проектирования. Шаблон – это очень краткое описание проблемы и решения и пример кода на каком-нибудь объектно-ориентированном языке. Для детального понимания шаблонов нужен определенный уровень абстрактного мышления – то есть в каком-то куске кода нужно видеть, что это, например, эталонный Decorator, хотя это слово может нигде не использоваться.
Большинство классов пакета java.io являются достаточно эталонными реализациями либо шаблона Adapter, либо шаблона Decorator.
Adapter и Decorator – это шаблоны GoF. Сюда входят классы типа:
InputStream, OutputStream: BufferedInputStream, BufferedOutputStream, ZipInputStream, ZipOutputStream и т.д. – это символьные потоки ввода-вывода.
Reader, Writer: BufferedReader, BufferedWriter.
DataInput, DataOutput: DataInputStream, DataOutputStream – потоки данных, ориентированные на примитивные данные Java.

У нас есть реальные источники данных, например: file, internet, audio, video, byte, char, String. Нам нужны классы, которые умеют из этих источников данных получать экземпляры InputStream или OutputStream. Это основная идея шаблонов Adapter и Decorator – создать класс, у которого есть «два конца»:

OutputStream dst = new FileOutputStream(“d:/tmp.txt”);

То есть с одной стороны – это OutputStream, а с другой – файл.
Обычно Adapter и Decorator строят через анонимные классы:

DataInput src = new DataInputStream(
new GZIPInputStream(
new BufferedInputStream(
new ByteArrayInputStream(rawData))));

– в таком случае не возникает проблем с тем, как именовать переменные.



В следующей теме мы рассмотрим: Garbage Collector

Источник: http://becomejavasenior.com/courses/?utm_source=Java+Email+Courses&utm_campaign=aa710df388-JavaRangerBasicIntro&utm_medi
Категория: Java Ranger Basic | (06.10.2015) W
Просмотров: 377 | Теги: Basic, ranger, java | Рейтинг: 0.0/0
Всего комментариев: 0
avatar