FilterStream в Java

FilterInputStream, FilterOutputStreamабстрактные классы для создания собственных потоков или добавления функционала к существующим.

В примере ниже создается класс расширяющий FilterInputStream, в котором мы реализуем свой поток байтового ввода. Этот созданный нами поток изменяет консольный байтовый ввод System.in так, чтобы он возвращал номер в таблице ASCII введенного пользователем в консоль символа, но сдвинутого на 13 символов в этой таблице.

Пример программы:

import java.io.*; import java.util.*; class Rot13InputStream extends FilterInputStream { // Переданный в конструктор поток i public Rot13InputStream(InputStream i) { // Передаем в конструктор класса родителя через super. super(i); // Там этот поток сохраняется. // И будет доступен здесь в наследнике через in, // которым мы пользуемся ниже. } // Переопределим read, чтобы он возвращал сдвинутое значение public int read() throws IOException { // С помощью read считываем символ потоком in, // переданный сюда через конструктор, // и передаем его в созданный нами метод rot13. return rot13(in.read()); } // Сдвиг на 13 символов public int rot13(int c) { // Сильно не разбирайтесь в коде ниже. Просто знайте, // что он сдвигает номер символа в ASCII на 13 символов. if ((c >= ‘A’) && (c <= 'Z')) c = (((c - 'A') + 13) % 26) + 'A'; if ((c >= ‘a’) && (c <= 'z')) c = (((c - 'a') + 13) % 26) + 'a'; return c; // Этот сдвинутый номер возвращается } } class FilterStreamLesson { public static void main(String[] args) { try { Rot13InputStream b13is = new Rot13InputStream(System.in); // Воспользуемся переопределенным нами read() // в Rot13InputStream, который будет сдвигать номер // введенного в поток символа на 13 значений // в таблице ASCII и возвращать сдвинутый номер. System.out.println(b13is.read()); } catch (Exception e) { // Обработаем возможную ошибку e.printStackTrace(); } } }

Вывод:

Номер символа а в таблице ASCII – 97, но поскольку мы сдвинули его на 13 символов выводиться 110.

ObjectStream в Java

ObjectInputStream, ObjectOutputStreamдля сериалиации/десериализации. Для сохранения копии объекта в поток (в файл, например) для восстановления его потом (десереализации).

Пример программы:

import java.io.*; import java.util.*; class ObjectStreamLesson{ public static void main(String[] args) { // сериализация try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“person.dat”))) { Person p = new Person(“Mike”, 25, 178, false); // сериализуем объект p в файл person.dat oos.writeObject(p); } catch(Exception ex){ System.out.println(ex.getMessage()); } // десериализация try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“person.dat”))) { // десериализуем объект p из файла person.dat Person p = (Person) ois.readObject(); // выведем его данные на консоль с помощью printf System.out.printf(“Name: %s \t Age: %d \n”, p.getName(), p.getAge()); } catch(Exception ex){ System.out.println(ex.getMessage()); } } } // чтобы сериализовать, класс должен быть Serializable class Person implements Serializable{ private String name; private int age; private double height; private boolean married; Person(String n, int a, double h, boolean m){ name = n; age = a; height = h; married = m; } String getName() { return name; } int getAge() { return age; } double getHeight() { return height; } boolean getMarried() { return married; } }

Вывод:

То есть мы сохраняем в файл копию какого-либо объекта и когда она нам будет нужна в нашей программе достаем ее.

OutputStreamWriter в Java

OutputStreamWriterмост между символьными и байтовыми потоками.

Пример программы:

import java.io.*; import java.util.*; class OutputStreamWriterLesson { public static void main(String[] args) { try { FileOutputStream outputStream = new FileOutputStream(“person.txt”); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream); // OutputStreamWriter конвертирует записываемые в него // символы в байты и эти байты записываются в файл байтовым // потоком, который был обернут в OutputStreamWriter. // В нашем случае FileOutputStream String str = “My Some Text!”; // Как видим записываем мы символы. То есть String, // OutputStreamWriter конвертирует String в байты // и передает байтовому потоку FileOutputStream // для вывода в файл. outputStreamWriter.write(str); // Также с помощью flush достаем FileOutputStream // из обертки OutputStreamWriter чтобы записать в него байты. outputStreamWriter.flush(); } catch (Exception e) {} } }

Вывод:

В итоге в файле можно увидеть строку str.

PushbackInputStream в Java

PushbackInputStream – прочитав несколько байтов входного потока с помощью inpsrream.read() бывает необходимо вернуться и прочитать эти же уже прочитанные ранее байты еще раз.

Делается с помощью inpsrteam.unread().

Пример программы:

import java.io.*; import java.util.*; class PushbackStream { public static void main(String[] args) { try { String str = “Hello world!!!”; byte b[] = str.getBytes(); ByteArrayInputStream bin = new ByteArrayInputStream(b); PushbackInputStream push = new PushbackInputStream(bin); // читаем первый символ System.out.print((char)push.read()); // Возвращаем его обратно. // То есть сейчас мы извлекли первый элемент ‘H’ из str // и если мы вызовем System.out.print((char)push.read()); // еще раз, то извлечется уже второй ‘e’. А мы хотим // опять прочитать первый. Для этого мы можем // вставить его перед ‘e’ и прочитать его еще // раз вместо ‘e’. На самом деле нам не обязательно // вставлять именно ‘H’ можно вставить любой символ. // Важная ремарка, что сама строка str // при всех этих манипуляциях не изменяется. push.unread(‘H’); // читаем снова первый возвращенный символ System.out.print((char)push.read()); // дальше будет читать со второго символа System.out.print((char)push.read()); System.out.print((char)push.read()); System.out.print((char)push.read()); } catch (Exception e) {} } }

Вывод:

Как видим, мы прочитали первый символ два раза. То есть мы прочитали его, потом вернули и прочитали его еще раз.

PipedStream в Java: передача данных между потоками

PipedInputStream, PipedOutputStream – применяется в многопоточной среде. Потоки в слове многопоточной, это не те потоки, которые мы сейчас изучаем (сейчас мы изучаем потоки ввода вывода). Эти же потоки понимайте как куски кода, которые выполняются параллельно. То есть в одном потоке один кусок кода, в другом другой и т.д, но главное все они выполняются параллельно друг другу.

PipedInputStream, PipedOutputStream связывают два потока I/O для для того чтобы они могли обмениваться информацией друг с другом.

Для передачи каких-либо данных между разными потоками лучше всего использовать этот класс.

Хотя потоки мы пока не разбирали, всё равно приведем пример.

Пример программы:

import java.io.*; import java.util.*; class PipedStreamLesson { // Например, есть 2 независимых потока: ThreadA и ThreadB. // Их классы создаются снизу после класса PipedStreamLesson. // Это не те потоки, которые мы сейчас изучаем // (сейчас мы изучаем потоки ввода-вывода). // Эти же потоки понимайте как два куска кода, // которые выполняются параллельно. // То есть содержимое метода run() в ThreadA выполняется // параллельно содержимому run() в ThreadB. public static void main(String[] args) { // Создаем концы канала: выходной и входной. PipedInputStream pis; PipedOutputStream pos; try { // Связываем в единый канал // для передачи данных между ними. pis = new PipedInputStream(); pos = new PipedOutputStream(pis); // Запускаем потоки. // После этого содержимое методов run // в этих классах начнет выполняться параллельно. new ThreadB(pis).start(); new ThreadA(pos).start(); // Также в эти потоки передаем связанные // каналы pis и pos, которые будут // использоваться для пересылки и считывания данных. } catch (Exception ex) { System.out.println(ex.getMessage()); } } } class ThreadA extends Thread { PipedOutputStream pos; ThreadA(PipedOutputStream pos) { this.pos = pos; } @Override public void run() { try { byte[] bytes = new byte[] {‘a’, ‘g’, ‘b’, ‘c’, ‘6’}; for (byte b : bytes) { // Используем переданный в конструктор pos // для передачи массива bytes в ThreadB. pos.write(b); Thread.sleep(1000); } } catch (Exception e) { e.printStackTrace(); } } } class ThreadB extends Thread { PipedInputStream pis; ThreadB(PipedInputStream pis) { this.pis = pis; } @Override public void run() { try { int b = 0; // pis считывает данные, передаваемые pos // из ThreadA. while ((b = pis.read()) != -1) { System.out.println((char) b); } } catch (Exception e) { e.printStackTrace(); } } }

Вывод:

Как видим данные успешно пересланы в другой поток и выведены им на консоль.

SequenceInputStream в Java

SequenceInputStream – сливает потоки в один поток.

Он считывает от первого byte до последнего byte первого InputStream, затем делает то же самое со следующим InputStream и т.д. до последнего InputStream и объединяет их всех в один InputStream.

Допустим, есть два файла person1 и person2 по пути C:/HTML/somedata/:

Теперь давайте объединим два файловых потока, которые читают из этих файлов в один, и, таким образом, сможем читать данные из обоих файлов через один SequenceInputStream.

import java.io.*; import java.util.*; class SequenceStream { public static void main(String[] args) { try { FileInputStream is1 = new FileInputStream(“C:/HTML/somedata/person1.txt”); FileInputStream is2 = new FileInputStream(“C:/HTML/somedata/person2.txt”); // объединяем SequenceInputStream is = new SequenceInputStream(is2, is1); // выведем содержимое обоих файлов через буферизованные потоки BufferedInputStream in = new BufferedInputStream(is); BufferedOutputStream out = new BufferedOutputStream(System.out); int ch; while ((ch = in.read()) != -1) { out.write((char) ch); out.flush(); } } catch (Exception e) {} } }

Вывод:

StringReader и StringWriter в Java

StringReader, StringWriter – потоки, которые хранят строку в себе с которой мы работаем через эти потоки как с любыми другими источниками дынных (фалами например).

Как раньше например мы записывали или выводили из консоли теперь будем записывать в строку или выводить из строки.

ByteArrayInputStream, ByteArrayOutputStream – аналог только работаем с массивом байтов вместо строки.

Пример программы:

import java.io.*; import java.util.*; class StringWRLesson { public static void main(String[] args) { try { String s = “data”; // Строчка ниже – ключевая: мы «превратили» строку в Reader. // И теперь можем работать со строкой как с объектом Reader. Reader reader = new StringReader(s); // можем сделать строку (поток) буферезированной. BufferedReader br = new BufferedReader(reader); String line = br.readLine(); // считать строку System.out.println(line); Writer writer = new StringWriter(); // Пишем какую-то строку в Writer // для дальнейшей записи ее в String переменную. writer.write(line + “some text”); // получаем текст, который был записан во Writer String result = writer.toString(); System.out.println(result); } catch (Exception e) {} } }

Вывод:

BufferedStream в Java

BufferedInputStream, BufferedOutputStreamчтение байтового потока и запись в байтовый поток с добавлением буфера для улучшения производительности.

Это класс обертка для InputStream с буферизацией.

Благодаря буферизации потоки, которые переданы в конструктор BufferedInputStream будут читать данные из буфера маленькими порциями, а буфер, чтобы сэкономить время и силы, читает их из потока источника большими порциями.

Пример программы:

import java.io.*; import java.util.*; class BufferedStreamLesson{ public static void main(String[] args) { String text = “Hello world!”; byte[] buffer = text.getBytes(); //ByteArrayInputStream, ByteArrayInputStream очевидно //для работы с массивами байтов //(читать из массива байтов/писать в массив байтов). ByteArrayInputStream in = new ByteArrayInputStream(buffer); //теперь in и System.out буферизованные что улучшает //производительность. BufferedInputStream bis = new BufferedInputStream(in); BufferedOutputStream bos=new BufferedOutputStream(System.out); try{ int ch; while((ch=bis.read()) != -1) { bos.write((char)ch); //только что мы записали байт в //буферизованный вывод BufferedOutputStream //а для записи байта в поток, который //обернут в BufferedOutputStream //необходимо сделать flush bos.flush(); } } catch(Exception e){ System.out.println(“gewgwg”); } } }

Вывод:

DataStream в Java

DataInputStream DataOutputStreamчтение байтового потока и запись в байтовый поток в формате примитивных типов данных.

Пример программы:

import java.io.*; import java.util.*; class DataStreamLesson{ public static void main(String[] args) { try { FileOutputStream fileOutputStream = new FileOutputStream(“double.txt”); FileInputStream fileInputStream = new FileInputStream(“double.txt”); // В данном примере файловый ввод/вывод. // Запись в формате примитивных типов // через файловый ввод. DataInputStream dis = new DataInputStream(fileInputStream); // Чтение в формате примитивных типов // через файловый вывод. DataOutputStream dos = new DataOutputStream(fileOutputStream); // Запись double числа в файл. dos.writeDouble(56.45); // Ниже можно увидеть, что мы считали только // что записанное в файл double число из файла // в переменную double благодаря методу readDouble(). // То есть это тот поток, который нужен, когда // необходимо считать откуда-то какой-то тип данных // и, например, записать его в переменную этого типа. // Есть методы и для других типов данных, // например readChar, writeChar и тому подобное. // Чтение в double переменную из файла только // что записанного double числа. double inpStrDouble = dis.readDouble(); System.out.println(inpStrDouble); } catch (Exception e) {} } }

После dos.writeDouble(56.45); в файл double.txt записывается число 56.45 (в формате double, поэтому оно так выглядит в файле).

С помощью double inpStrDouble = dis.readDouble(); считываем из файла число, которое в формате double, в переменную double.

FileStream в Java: чтение и запись файлов

FileOutputStream, FileInputStreamдля чтения файла и записи в файл.

В конструкторе должен быть указываем путь к файлу с которым будем совершать ввод/вывод.

Пример программы:

import java.io.*; import java.util.*; class FileStreamLesson { public static void main(String[] args) { try { // FileOutputStream – для записи в файл. В конструктор // FileOutputStream передаем в виде строки путь к файлу // в который будем записывать. // Если полноценный путь не указан, а только файл, значит // файл, который мы собираемся читать/записывать находится // в той же папке где и текущий файл java в который вы // сейчас смотрите. FileOutputStream fileOutputStream = new FileOutputStream(“person.txt”); // FileInputStream – для чтения файла. Также передаем путь FileInputStream fileInputStream = new FileInputStream(“person.txt”); // Поскольку это OutputStream и InputStream значит, что // читать из файла или записывать в файл будем байты. // Поэтому чтобы записать в файл строку String // ее сначала нужно преобразовать в массив байтов, // и а его уже записывать в файл. Ниже это делаем. // Строка которую будем записывать String str = “Some Text”; // преобразовываем строку в байты byte[] buff = str.getBytes(); // через поток записи в файл записываем туда массив байт fileOutputStream.write(buff, 0, buff.length); // Теперь прочитаем из файла person.txt // только что нами записанную строку. // available возвращает текущее количество байтов в файле // и пока оно больше нуля цикл продолжается. int i; while (fileInputStream.available() > 0) { // с помощью read на каждой итерации цикла // считываем один байт и записываем в переменную int. // и после read возвращаемое количество байтов // через метод available уменьшается на 1 i = fileInputStream.read(); // также необходимо привести к символу // полученный из файла байт System.out.println((char) i); } } catch (Exception e) { } } }

После fileOutputStream.write(buff,0,buff.length); в файл person.txt записывается “Some Text” и файл выглядит так:

Циклом побайтно считается файл с помощью FileInputStream: