JavaRush /Курсы /Java Collections /StringReader, StringWriter

StringReader, StringWriter

Java Collections
2 уровень , 3 лекция
Открыта

— Привет, Амиго!

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

— Сегодня я хочу тебе рассказать про классы StringReader и StringWriter. Принципиально нового тут для тебя будет мало, но иногда эти классы бывают очень полезны. И, как минимум, я хочу, чтобы ты знал, что они есть.

Эти классы – это простейшие реализации абстрактных классов Reader и Writer. И практически аналоги FileReader и FileWriter. Но, в отличие от них, они работают не с данными в файле на диске, а со строкой (String) находящейся в памяти Java-машины.

— А зачем нужные такие классы?

— Иногда нужны. StringReader – это, фактически, переходник между классом String и Reader. А StringWriter – это строка, которая унаследована от Writer. М-да. Сама вижу, что объяснение не очень. Давай лучше для начала рассмотрим пару примеров.

Например, ты хочешь проверить, как работает твой метод, который должен вычитывать данные из переданного в него объекта Reader. Вот как это можно сделать:

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

 //это строчка – ключевая: мы «превратили» строку в Reader
 StringReader reader = new StringReader(test);

 executor(reader);
} 

public static void executor(Reader reader) throws Exception
{
 BufferedReader br = new BufferedReader(reader);
String line;
while ((line = br.readLine()) != null)
 {
  System.out.println(line);
 }
}

— Т.е. мы просто взяли строку, обернули ее в StringReader и передали вместо объекта Reader? И из нее все будет читаться, как и надо?

— Ага. Гм. А в этом есть смысл. А теперь проверим, как работают методы StringWriter. Для этого усложним пример. Теперь он будет не просто читать строки, и выводить их на экран, а разворачивать их задом наперед и выводить в объект writer. Пример:

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

 //Создаем объект StringWriter
 StringWriter writer = new StringWriter();

 //переписываем строки из Reader во Writer, предварительно развернув их
 executor(reader, writer);

 //получаем текст, который был записан во Writer
 String result = writer.toString();

 //выводим полученный из Writer’а текст на экран
 System.out.println("Результат: "+result);
}

public static void executor(Reader reader, Writer writer) throws Exception
{
 BufferedReader br = new BufferedReader(reader);
String line;

  //читаем строку из Reader’а

while ((line = br.readLine()) != null)
 {
  //разворачиваем строку задом наперед
  StringBuilder sb = new StringBuilder(line);
  String newLine = sb.reverse().toString();

  //пишем строку в Writer
  writer.write(newLine);
 }
}

Мы создали объект StringWriter, внутри которого есть строка, в которой хранится все, что в этот writer пишут. А чтобы ее получить, надо всего лишь вызвать метод toString().

— Гм. Как-то все слишком просто получается. Метод executor работает с объектами потокового ввода reader и writer, а в методе main мы работаем уже со строками.

Все действительно так просто?

— Ага. Чтобы преобразовать строку в Reader достаточно написать:

Создание Reader из String
String s = "data";
Reader reader = new StringReader(s);

А преобразовать StringWriter к строке еще проще:

Получение String из Writer
Writer writer = new StringWriter();
/*тут пишем кучу данных во writer */
String result = writer.toString();

— Отличные классы, как по мне. Спасибо за рассказ, Элли.

Комментарии (59)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Артём Сёмкин Уровень 47
2 апреля 2025
StringReader — это класс, который позволяет читать данные из строки как из потока символов. Он полезен, когда у тебя есть строка, и ты хочешь обработать её так, будто она поступает из какого-то источника ввода (например, файла или сети), используя методы чтения, такие как read(). Зачем нужен? -Удобен для тестирования кода, который ожидает поток ввода (Reader), но ты хочешь подать ему просто строку. -Позволяет парсить строку посимвольно или построчно без необходимости вручную управлять индексами. -Интеграция с другими API, которые работают с абстрактным классом Reader.
{Java_Shark} Уровень 36
17 января 2025
++
Denis Odesskiy Уровень 47
30 августа 2024
Многие спрашивают зачем нужны эти классы. Уделив этому вопросу достаточно времени, вы пойметё что они очень даже нужны! Ну например, захотите вы написать свой парсер например, или генератор текста, тогда они и ещё как понадобятся... Например спарсить какие-то данные потоковые в JSON е или xml, да мало ли... Вообще если работать с какими то API где потоковые данные и надо преобразовать в текст. Ну и для тестов тоже. Также мы можем работать, манипулировать, с какими-то данными в памяти, не записывая их в файл... Т.е. вы можете спарсить что-то, затем манипулировать этими данными, например провести сортировку книг по авторам, и только затем куда-то сохранить. В общем это удобно. Ниже я написал, примитивный пример, но вывести на консоль данные можно и без этих классов. Но допустим у нас какой-то сервис, который занимается, получением свежих новинок книг в нашем магазине, а далее отсылает этот список нашим подписчикам. Допустим мы получаем эти данные в каком-то формате, парсим во что-то читаемое и... И тут предположим, что у нас есть в подписчиках библиотека и им важно получить список книг, но уже отсортированный по авторам. И есть просто подписчики-читатели, и им важнее всего получить список отсортированный по цене. При этом мы не хотим хранить эти данные на диске в файле, записывать их, читать и т.п., а хотим все сделать на лету, вот тут-то эти классы и нужны. Вот по-быстрому накидал пример, простенького парсинга (не пинайте ногами, просто пример на коленке). Представьте что вы работаете с открытым сетевым соединением и вам приходят данные, скажем в виде строки xml, вы должны их спарсить:
Denis Odesskiy Уровень 47
30 августа 2024
Импорты не влезли в сообщение , добавьте сами.

public class Parser {
    public static void main(String[] args) {
        // Путь к файлу с XML.
        String filePath = "src/com/testall/string/library.xml";
        StringWriter output = new StringWriter(); // StringWriter для записи результатов.

        try (FileReader fileReader = new FileReader(filePath)) {
            // Создаем SAX-парсер.
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser parser = factory.newSAXParser();

            // Парсим XML и записываем результат в StringWriter.
            parser.parse(new InputSource(fileReader), new MyHandler(output));

            // Выводим содержимое.
            System.out.println("Parsed Output:\n" + output.toString());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Класс-обработчик для обработки событий парсинга.
    static class MyHandler extends DefaultHandler {
        private final StringWriter writer;

        public MyHandler(StringWriter writer) {
            this.writer = writer;
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            writer.write("Start Element: " + qName + "\n");
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            writer.write("End Element: " + qName + "\n");
        }
        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            String content = new String(ch, start, length).trim();
            if (!content.isEmpty()) {
                writer.write("Element Value: " + content + "\n");
            }
        }
    }
}
Строка может приходить как-то так String xmlData = "<root><element>Network Data</element></root>";
Shhopat Уровень 51
17 августа 2024
что все жалуются. итак много инфы тут и лучше будет если повторять темы с одновременным раскрытием некоторых скрытых моментов уже пройденной темы.
22 февраля 2024
Блин только из-за перфекционизма решаю эти задачи и лекции, одно и тоже. Лучше бы новые темы связанные объясняли и давали бы задачи на многогранные пройденные темы.
Greemka4 Уровень 1
28 января 2024
Когда это закончится....
partiec Уровень 33
6 октября 2023
Гм.
Rolik Уровень 41
7 мая 2023
Навернули от души. Вот вам пример, а что такое полиморфный метод вы узнаете тем через 20. Зачет.
Kurama Уровень 50
14 декабря 2022
StringReader StringBuffer StringBuilder String ... Чтобы развернуть текст... А не дохрена?
Daniel Уровень 51
8 марта 2023
... делать троллейбус. Но зачееем?...
Denis Odesskiy Уровень 47
30 августа 2024
У класса String нет методов развернуть текст... Но, можно написать свой, разными способами:

package com.testall.string;

public class MyReverseString {
    public static void main(String[] args) {
        // Test.
        String str1 = "Hello World!";
        String str2 = "-123.04";
        String str3 = "Мама мыла раму.";
        String str4 = "43" + -51;
        String str5 = "   ";
        String str6 = "";
        String str7 = null;

        String pattern = "%s -----> %s%n";

        System.out.printf(pattern, str1, reverseString(str1));
        System.out.printf(pattern, str2, reverseString(str2));
        System.out.printf(pattern, str3, reverseString(str3));
        System.out.printf(pattern, str4, reverseString(str4));
        System.out.printf(pattern, str5, reverseString(str5));
        System.out.printf(pattern, str6, reverseString(str6));
        System.out.printf(pattern, str7, reverseString(str7));
    }

    /**
     * Reverses the given string using recursion.
     *
     * <p>This method takes a string as input and recursively calls itself,
     * removing the first character each time until the string is empty.
     * It then constructs the reversed string by appending the first character
     * of the current substring to the result of the recursive call.</p>
     *
     * @param str The string to be reversed. If the string is empty, it returns an empty string.
     * @return The reversed string.
     * @author Denis Odesskiy
     */
    public static String reverseString(String str) {
        if (str.isEmpty()) {
            return str;
        }
        return reverseString(str.substring(1)) + str.charAt(0);
    }
}
28 октября 2022
Функционал конечно просто невероятный, но никак не могу докумекать куда все это добро применять ))