Главная страница

Поток Что такое InputStream и OutputStream


Скачать 33.32 Kb.
НазваниеПоток Что такое InputStream и OutputStream
Дата26.09.2022
Размер33.32 Kb.
Формат файлаdocx
Имя файлаRevyu_5 (1).docx
ТипДокументы
#698537

**Поток

1. Что такое InputStream и OutputStream.

Базовый абстрактный класс InputStream представляет классы, которые получают данные из различных источников :- массив байтов- строка (String)- файл- канал (pipe): данные помещаются с одного конца и извлекаются с другого- последовательность различных потоков, которые можно объединить в одном потоке- другие источники (например, подключение к интернету)
Класс OutputStream - это абстрактный класс, определяющий потоковый байтовый вывод. В этой категории находятся классы, определяющие, куда направляются ваши данные: в массив байтов (но не напрямую в String; предполагается что вы сможете создать их из массива байтов), в файл или канал.

Создать экземпляры этих классов нельзя.

2. Почему важно закрывать потоки.

При закрытии потока освобождаются все выделенные для него ресурсы, например, файл. В случае, если поток окажется не закрыт, может происходить утечка памяти.

3. Какие потоки можно не закрывать (не вызывать метод close()).

Можно не закрывать вложенные потоки, системные потоки, те, которые не используют ресурсы.

4. Что делает метод available().

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

Доступный метод для класса InputStream всегда возвращает 0.

5. Можно ли использовать flush() для не буферизированного потока и что будет.

Можно, ничего не произойдет

6. На каком паттерне основана иерархия потоков ввода/вывода.

На паттерне «Декоратор». В этом паттерне при создании потока нужно использовать несколько объектов

7. Что делает метод read. Почему он возвращает int а не byte. Почему он не может возвращать byte.

Метод читает следующий байт из входящего потока. Когда метод ничего не может считать (конец потока), возвращается -1.
Потому что нужно нужен такой тип, который может вместить 1 байт, плюс одно служебное значение -1 (обозначающее конец потока)
Диапазон byte в Java лежит от -128 до 127, а возвращаемое значение метода read() лежит в диапазоне от 0 до 255

8. Что вернет метод read(), если он считывает файл и ему встречается байт равный -1.

Получим 255, происходит из-за побитового сдвига.

9. Что возвращает перегруженный read. Какое максимальное значение вернет.

Возвращает код введенного символа из консоли. От 0 до 65635.

10. Как работает метод read()?

Метод read() - возвращает значение целого типа очередного символа, доступного во входном потоке; Метод read(byte arr) - метод для массового считывания данных, который считывает максимум байтов (не более arr.length) из потока, входящих данных в аргумент массива arr и возвращает фактическое количество байтов, считанных из потока;

11. Гарантируется ли запись данных в файл при вызове flush().

Не гарантируется

Flushметод класса OutputStream используется для сброса содержимого буфера в выходной поток. Буфер — это часть памяти, которая используется для хранения потока данных (символов). Иногда эти данные отправляются на устройство вывода только тогда, когда буфер заполнен. Метод flush для OutputStream ничего не делает.

Таким образом, вам нужно вызвать flush, когда вы хотите записать данные перед закрытием потока и до того, как буфер будет заполнен (когда буфер заполнен, писатель начинает запись, не дожидаясь вызова сброса).

Исходный код класса FileOutputStream не имеет пользовательской версии метода flush. Таким образом flush, используемый метод является версией своего суперкласса OutputStream.

С буферизованными модулями записи метод close вызывается явно flush.

Когда вы записываете данные в поток, он не записывается сразу и буферизуется. Поэтому используйте flush(), когда вам нужно убедиться, что все ваши данные из буфера записаны. Мы должны быть уверены, что все записи завершены до закрытия потока, и именно поэтому flush() вызывается в файле/буферизованной записи close().

**Scanner

1. Для чего нужен Scanner.

Класс Scanner используется для получения (считывания) данных, введенных пользователем в виде String, byte, short, int, long, float, double.

2. Что такое токен в Scanner.

Токен (или маркер) представляет собой серию цифровых или буквенно-цифровых символов, которая заканчивается разделителем. Разделителем может быть символ табуляции, возврат каретки (перевод строки или же просто ‘Enter’), конец файла или пробел.

3. Отличие Scanner’a от BufferedReader’a.

Scanner предназначен для разбора любого текста и, ввода с терминала, как частный случай. Scanner работает медленно, но зато предоставляет очень широкий API с кучей удобных методов. BufferedReader нужен, чтобы буфферизовать чтение с любого потока. Как частный случай, можно буфферизовать ввод с терминала. Он работает быстрее, потому что читает часть входных данных в буфер, откуда они быстрее читаются по частям, то есть обращение к консоли происходит реже.

4. Есть ли у сканера буфер.

Из кода java.util.Scanner :

// Internal buffer used to hold input

**Файл

1. Абсолютный и относительный путь.

Полный или абсолютный путь — это путь, который указывает на одно и то же место в файловой системе, вне зависимости от текущего рабочего каталога или других обстоятельств. ... Относительный путь представляет собой путь по отношению к текущему рабочему каталогу пользователя или активных приложений.

2. Методы File

  • boolean createNewFile(): создает новый файл по пути, который передан в конструктор. В случае удачного создания возвращает true, иначе false

  • boolean delete(): удаляет каталог или файл по пути, который передан в конструктор. При удачном удалении возвращает true.

  • boolean exists(): проверяет, существует ли по указанному в конструкторе пути файл или каталог. И если файл или каталог существует, то возвращает true, иначе возвращает false

  • String getAbsolutePath(): возвращает абсолютный путь для пути, переданного в конструктор объекта

  • String getName(): возвращает краткое имя файла или каталога

  • String getParent(): возвращает имя родительского каталога

  • boolean isDirectory(): возвращает значение true, если по указанному пути располагается каталог

  • boolean isFile(): возвращает значение true, если по указанному пути находится файл

  • boolean isHidden(): возвращает значение true, если каталог или файл являются скрытыми

  • long length(): возвращает размер файла в байтах

  • long lastModified(): возвращает время последнего изменения файла или каталога. Значение представляет количество миллисекунд, прошедших с начала эпохи Unix

  • String[] list(): возвращает массив файлов и подкаталогов, которые находятся в определенном каталоге

  • File[] listFiles(): возвращает массив файлов и подкаталогов, которые находятся в определенном каталоге

  • boolean mkdir(): создает новый каталог и при удачном создании возвращает значение true

  • boolean renameTo(File dest): переименовывает файл или каталог

к

3. Как создать файл на компьютере с помощью java.

Для создания нового файла в Java чаще всего используется класс java.io.File . Во время инициализации объекта File мы должны предоставить ему имя файла, а затем создать сам файл вызовом метода createNewFile()

4. Как удалить директорию с файлами. Что если в ней есть вложенные директории.

FileUtils.deleteDirectory или рекурсивным удалением walkFileTree с методом delete()

5. В чём отличие File от Path.

  1. File — это класс, Path — это интерфейс.

  2. File — это старый способ доступа к файловой системе, Path — это новый рекомендуемый способ.

  3. Path допускает работу с файлами на виртуальных файловых системах, а File нет.

  4. Методы работы с ФС через объект Path при ошибках ввода-вывода бросают исключения; методы работы с File при ошибках возвращают false.

**Клонирование

1. Что такое клонирование. Как реализовано клонирование в Java.

Иногда необходимо на основе существующего объекта создать второй такой же - то есть создать его клон. Это процесс в Java называется клонированием.

Мы можем использовать метод clone(). (класс должен реализовывать Cloneable)

2. Клонирование объекта. Глубокое и поверхностное.

По умолчанию, клонирование в Java является поверхностным, т.е. Object class не знает о структуре класса, которого он копирует. Новый объект просто содержит в себе ссылку на старый. При глубоком создается совсем новый объект с новой ссылкой.

Поверхностное клонирование применяется только с примитивными полями.

Глубокое с примитивными и ссылочными.

3. Чем отличается копирование от клонирования.

Операция клонирования (Edit • Clone) отличается от дублирования (копирования) двумя особенностями. Во-первых, клон наследует свойства контура и заполнения исходного объекта и сохраняет связь с этими свойствами: изменение свойств исходного объекта вызывает соответствующие изменения у клона. Во-вторых, операция клонирования «одноступенчатая»: нельзя создать клон от клона.

4. Можно ли клонировать String, массив String.

clone - это метод класса Object. Чтобы класс был "cloneable", он должен реализовать интерфейс marker Cloneable . класс String не реализует этот интерфейс и не переопределяет метод клонирования, поэтому возникает ошибка.

Массив стрингов клонировать можно.

**Сериализация

1. Что такое сериализация и десериализация.

Сериализация — это процесс сохранения состояния объекта в последовательность байт.

Десериализация — это процесс восстановления объекта из этих байт.

Зачем вообще нужна сериализация?

1) Данные в памяти "живут", до момента завершения приложения. Сериализация позволяет записать объекты в файлы и, таким образом, восстановить их затем.
2) Сериализация предоставляет универсальный механизм обмена данными между компонентами приложения или узлами в интернете.

А что если у нас Serializable класс содержит поля, в которых объекты не Serializable?
1) В таком случае код скомпилируется.
2) Но в рантайме при попытке сериализации , когда мы дойдем до этого поля и объекта, мы получим NotSerializableException.
2. Назовите несколько форматов сериализации.

JSON (JavaScript Object Notation), YAML (Yet Another Markup Language), XML, BSON (Binary JSON), Position Based Protocol

3. Как сериализовать объект класса.

1) Класс объекта должен реализовывать интерфейс Serializable
2) Создать поток ObjectOutputStream (oos), который записывает объект в переданный OutputStream.
3) Записать в поток: oos.writeObject(Object);
4) Закрыть поток. Сделать oos.flush() и oos.close()

Что нужно сделать, чтобы ДЕсериализовать объект?

1) Класс объекта должен реализовывать интерфейс Serializable
2) Создать поток ObjectInputStream (ois), в который передать InputStream (instream) (из файла, из памяти...)
3) Получить объект и привести к нужному типу: MyObject my = (MyObject) ois.readObject(instream)

4. Что делать, если одно из полей сериализовывать не нужно.

- Добавить к полю модификатор transient. В таком случае после восстановления его значение будет null.

- Сделать поле static. Значения статических полей автоматически не сохраняются.

- Также можно написать свои методы read/writeObject или read/writeExternal и записать в них только те поля, которые нам нужны.

5. Как сериализовать статическое поле.

При использовании реализации Externalizable сериализовать и десериализовать статическое поле можно, но не рекомендуется этого делать, т.к. это может сопровождаться трудноуловимыми ошибками.

6. Externalizable vs Serializable

При записи Serializable класса весь контроль над сериализацией достается JVM. С помощью определения специальных методов можно кастомизировать его части. Метод readObject при этом обычно начинается с вызова стандартной части сериализации – ObjectInputStream.defaultReadObject().

Интерфейс Externalizable расширяет Serializable и добавляет методы записи и чтения writeExternal и readExternal. Входной и выходной потоки-аргументы в них представлены более абстрактно чем в специальных методах – интерфейсами ObjectInput и ObjectOutput.

Этот интерфейс позволяет реализовать полностью свой механизм сериализации, стандартно запишется только идентификатор класса. Никакой автоматической работы с классом-родителем также не предусмотрено. Методы readObject и writeObject игнорируются. Ключевое слово transient эффекта на Externalizable не имеет.

Externalizable объект в отличие от Serializable десерализуется не в обход конструктора, так что должен иметь конструктор без аргументов.

7. Что, если я не хочу сериализовывать поле. Что если при десериализации поменять тип.

Нужно использовать transient. Будет ошибка

8. Что будет если перед десериализцией изменится класс, почему будет выброшено исключение.

исходя из спецификации, будет исключение InvalidClassException. serialVersionUID при проверке не совпадёт.

9. Что будет при сериализации объекта у которого есть поле, и оно не Serializable.

В таком случае код скомпилируется. Но в рантайме при попытке сериализации, когда мы дойдем до этого поля и объекта, мы получим NotSerializableException.

10. Особенность сериализации поля final.

Поля с модификатором final сериализуются как и обычные. За одним исключением – их невозможно десериализовать при использовании Externalizable.

11. Какие поля не сериализуются.

1) static поля - они часть класса, а не объекта. Следовательно, они не указывают на состояние объекта.

2) transient поля - модификатор как раз и говорит о том, что "это поле не отмечает состояние объекта". Следовательно, его не нужно сериализовать.

Где ставится ключевое слово transient? Что оно означает?
1) Слово transient ("временный, переходный") - это модификатор для поля класса.
2) Если поле объявлено transient, это значит, что значение этого поля не нужно записывать при сериализации.
3) При восстановлении объекта у него б

Общие вопросы

1. Отличие пакетов IO и NIO, InputStream от Reader.

Классы java.nio поддерживают неблокирующий ввод-вывод, а java.io — блокирующий.

Классы java.nio предоставляют более низкоуровневый интерфейс, пользуясь которым можно писать более эффективные и масштабируемые программы.

Reader работает на уровне символов Unicode, InputStream — на уровне байт.

IO
1) Блокирующий ввод-вывод
Потоки ввода/вывода (streams) в Java IO являются блокирующими. Это значит, что когда в потоке выполнения (tread) вызывается read() или write() метод любого класса из пакета java.io.*, происходит блокировка до тех пор, пока данные не будут считаны или записаны. Поток выполнения в данный момент не может делать ничего другого.
2) Потокоориентированный ввод-вывод.
Потокоориентированный ввод/вывод подразумевает чтение/запись из потока/в поток одного или нескольких байт в единицу времени поочередно. Данная информация нигде не кэшируются. Таким образом, невозможно произвольно двигаться по потоку данных вперед или назад. Если вы хотите произвести подобные манипуляции, вам придется сначала кэшировать данные в буфере.

NIO
1) Неблокирующий ввод-вывод
Неблокирующий режим Java NIO позволяет запрашивать считанные данные из канала (channel) и получать только то, что доступно на данный момент, или вообще ничего, если доступных данных пока нет. Вместо того, чтобы оставаться заблокированным пока данные не станут доступными для считывания, поток выполнения может заняться чем-то другим.
2) Буфероориентированный ввод-вывод.
3) Селекторы
Селекторы в Java NIO позволяют одному потоку выполнения мониторить несколько каналов ввода. Вы можете зарегистрировать несколько каналов с селектором, а потом использовать один поток выполнения для обслуживания каналов, имеющих доступные для обработки данные, или для выбора каналов, готовых для записи.

2. Что такое System.in, что такое System.out.

Стандартный поток ввода (клавиатура) в Java представлен объектом — System.in .

А стандартный поток вывода (дисплей) — уже знакомым вам объектом System.out .

3. Какие интерфейсы реализует InputStream/ OutputStream/ Reader/ Writer.

DataInput и DataOutput

4. Что такое паттерн адаптер.

Паттерн Adapter, представляющий собой программную обертку над существующими классами, преобразует их интерфейсы к виду, пригодному для последующего использования.

5. Пример адаптера и декоратора из IO.

InputStreamReader – адаптер. Как и всякий адаптер, он преобразует один интерфейс к другому. В данном случае — интерфейс InputStream’a к интерфейсу Reader’a.

Декоратор динамически наделяет объект новыми возможностями. Пример – FilterInputStream

Reader и Writer

Символьные потоки имеют два основных абстрактных класса Reader и Writer, управляющие потоками символов Unicode. Класс Reader - абстрактный класс, определяющий символьный потоковый ввод. Класс Writer - абстрактный класс, определяющий символьный потоковый вывод. В случае ошибок все методы класса передают исключение IOException.


написать администратору сайта