— И это снова я.

— Привет, Элли!

— Сегодня я хочу тебе подробно рассказать про BufferedReader и BufferedWriter.

— Так ты мне уже рассказывала все про них. Ну ничего там сложного нет.

— Ок. Расскажи, как работает BufferedReader.

— BufferedReader — это как переходник в розетке с 110 к 220 вольт.

В конструктор объекта BufferedReader обязательно нужно передать объект Reader, из которого он будет читать данные. Объект BufferedReader читает из Reader’а данные большими кусками и хранит их у себя внутри в буфере. Поэтому чтение из пары BufferedReader+Reader быстрее, чем прямо из Reader.

— Верно. А BufferedWriter?

— Тут тоже все просто. Когда мы пишем в FileWriter, например, то данные сразу записываются на диск. Если мы часто пишем небольшие данные, то происходит много обращений к диску, что замедляет работу программы. А если мы используем BufferedWriter в качестве «переходника», то операция записи на диск ускорится. BufferedWriter, при записи в него, сохраняет переданные данные во внутреннем буфере, а когда буфер заполняется – пишет данные во Writer одним большим куском. Это гораздо быстрее.

— Гм. Все верно. А что ты забыл?

— После окончания записи у объекта BufferedWriter надо вызвать метод flush(), чтобы он записал данные из буфера во Writer, которые еще не записаны, т.е. буфер не заполнен до конца.

— А кроме того?

— А кроме того, пока буфер еще не записан во Writer, данные можно удалить и/или заменить на другие.

— Амиго! Я поражена! Да ты просто эксперт. Ладно, тогда я расскажу тебе о новых классах: ByteArrayStreamPrintStream.

Итак, ByteArrayInputStream и ByteArrayOutputStream.

Эти классы по сути чем-то похожи на StringReader и StringWriter. Только StringReader читал символы (char) из строки (String), а ByteArrayInputStream читает байты из массива байт (ByteArray).

StringWriter писал символы (char) в строку, а ByteArrayOutputStream пишет байты в массив байт у него внутри. При записи в StringWriter строка внутри него удлинялась, а при записи в ByteArrayOutputStream его внутренний массив байт тоже динамически расширяется.

Вот пример, который выводит в консоль полученную строку:

Чтение из объекта reader и запись в объект writer:
public static void main (String[] args) throws Exception
{
 String test = "Hi!\n My name is Richard\n I'm a photographer\n";
 StringReader reader = new StringReader(test);

 StringWriter writer = new StringWriter();

 executor(reader, writer);

 String result = writer.toString();

 System.out.println("Результат: "+result);
}

public static void executor(Reader reader, Writer writer) throws Exception
{
 BufferedReader br = new BufferedReader(reader);
String line;
 while ((line = br.readLine()) != null) {
    writer.write(line + '\n');
 }
}

Вот как он будет выглядеть, если тут работать не с символами, а с байтами:

Чтение из объекта InputStream и запись в объект OutputStream:
public static void main (String[] args) throws Exception
{
 String test = "Hi!\n My name is Richard\n I'm a photographer\n";
 InputStream inputStream = new ByteArrayInputStream(test.getBytes());

 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

 executor(inputStream, outputStream);

 String result = new String(outputStream.toByteArray());
 System.out.println("Результат: "+result);
}

public static void executor(InputStream inputStream, OutputStream outputStream) throws Exception
{
 BufferedInputStream bis = new BufferedInputStream(inputStream);
 while (bis.available() > 0)
 {
  int data = bis.read();
  outputStream.write(data);
 }
}

Тут все аналогично примеру выше. Вместо String – ByteArray. Вместо Reader – InputStream, вместо Writer – OutputStream.

Единственные еще два момента – это преобразование строки в массив байт и обратно. Как ты видишь, это делается довольно несложно:

Преобразование строки в массив байт и обратно
public static void main (String[] args) throws Exception
{
 String test = "Hi!\n My name is Richard\n I'm a photographer\n";
 byte[] array = test.getBytes();

 String result = new String(array);
 System.out.println("Результат: "+result);
}

Чтобы получить байты, которые уже добавлены в ByteArrayOutputStream, надо вызвать метод toByteArray().

— Ага. Аналогия с StringReader/StringWriter довольно сильная, особенно когда ты мне ее показала. Спасибо, Элли, действительно интересный урок.

— Куда это ты спешишь? У меня есть еще небольшой подарок – хочу рассказать тебе про класс PrintStream.

— PrintStream? В первый раз слышу о таком классе.

— Ага. Особенно, если не считать, что ты им пользуешься с первого дня, когда ты начал изучать Java. Помнишь System.out? так вот – System.out – это статическая переменная класса System типа… PrintStream! Именно оттуда растут ноги всех этих print, println и т.д.

— Ого. Как интересно. Я как-то ни разу и не задумывался. Расскажи подробнее.

— Гуд. Тогда слушай. Класс PrintStream был придуман для читабельного вывода информации. Он практически весь состоит из методов print и println. См. таблицу:

Методы Методы
void print(boolean b) void println(boolean b)
void print(char c) void println(char c)
void print(int c) void println(int c)
void print(long c) void println(long c)
void print(float c) void println(float c)
void print(double c) void println(double c)
void print(char[] c) void println(char[] c)
void print(String c) void println(String c)
void print(Object obj) void println(Object obj)
  void println()
PrintStream format (String format, Object ... args)
PrintStream format (Locale l, String format, Object ... args)

Также есть несколько методов format, чтобы можно было выводить данные на основе шаблона. Пример:

Преобразование строки в массив байт и обратно
String name = "Kolan";
int age = 25;
System.out.format("My name is %s. My age is %d.", name, age);
Вывод на экран:
My name is Kolan. My age is 25.

— Ага, помню, мы уже когда-то разбирали метод format у класса String.

— На этом все.

— Спасибо, Элли.