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

Ввод-вывод, доступ к файловой системе. Ревью 5. 1. Что такое InputStream и OutputStream


Скачать 37.74 Kb.
Название1. Что такое InputStream и OutputStream
АнкорВвод-вывод, доступ к файловой системе
Дата11.09.2022
Размер37.74 Kb.
Формат файлаdocx
Имя файлаРевью 5.docx
ТипДокументы
#671759

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


  • InputStream - это абстрактный класс , который описывает ввод потока и используется для чтения файлов, изображений, аудио, видео, веб-страница и т.д. это не имеет значения. Таким образом, InputStream считывает данные из источника по одному элементу за раз.




  • OutputStream - это абстрактный класс, который описывает потоковый вывод и используется для записи данных в файл, изображение, аудио и т.д. Таким образом, OutputStream записывает данные в пункт назначения по одному за раз.

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

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


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

  • Если используется конструкция try-with-resourse У нее есть специальный интерфейс AutoCloseble.



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

  • Метод возвращает количество байт, которое еще осталось в потоке


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

  • Можно

т.к исходя из документации, "среда хоста может выполнять свою собственную буферизацию, неизвестную Java. В этом случае запись можешь кэшироваться в буферах ОС".
Когда мы даем любую команду, потоки этой команды сохраняются в области памяти, называемой буфером (временная область памяти) на нашем компьютере. Когда вся временная область памяти заполнена, мы используем flush (), которая очищает все потоки данных и полностью их выполняет, а также дает новое пространство для новых потоков во временном расположении буфера. Буферизация в основном выполняется для повышения производительности ввода-вывода.
flush () очищает все потоки данных и полностью их записывает, а также дает новое пространство для новых потоков во временном расположении буфера. Но если буффер пустой (/ не попали данные через write) – то ничего записано не будет
6. На каком паттерне основана иерархия потоков ввода/вывода.


  • Объекты классов Java, которые используются для ввода/вывода, для обеспечения необходимой функциональности наслаиваются друг на друга. Такая модель взаимодействия объектов поддерживается в паттерне «Декоратор». В этом паттерне при создании потока нужно использовать несколько объектов.

  • Декоратор — это структурный паттерн, который позволяет добавлять объектам новые поведения на лету, помещая их в объекты-обёртки. Декоратор позволяет оборачивать объекты бесчисленное количество раз благодаря тому, что и обёртки, и реальные оборачиваемые объекты имеют общий интерфейс. 

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

  • Метод читает следующий байт из входящего потока. Когда метод ничего не может считать (конец потока), возвращается -1.

  • Потому что нужно нужен такой тип, который может вместить 1 байт, плюс одно служебное значение -1 (обозначающее конец потока)

  • Диапазон byte в Java лежит от -128 до 127, а возвращаемое значение метода read() лежит в диапазоне от 0 до 255.


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

  • 255.

  • а если -3 то 253


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

  • Максимально, read может ввести 65534 байта, т.к. 65535 это -1, индикатор ошибки. Однако максимальное число байтов, которое мож-
    но прочитать из файла, равно 65534; поскольку 65534 (или OXFFFF)
    является неотличимым от -1, поэтому будет возвращена ошибка.





  • int read() - возвращает представление очередного доступного символа во входном потоке в виде целого числа.

  • int read(char[] buffer) - пытается прочесть максимум buffer.length символов из входного потока в массив buffer. Возвращает количество символов, в действительности прочитанных из потока.

  • int read(char[] buffer, int offset, int length) - пытается прочесть максимум length символов, расположив их в массиве buffer, начиная с элемента offset. Возвращает количество реально прочитанных символов.


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

  • Если предполагаемое место назначения этого потока является абстракцией, предоставляемой базовой операционной системой, например файлом, то очистка потока гарантирует только то, что байты, ранее записанные в поток, передаются операционной системе для записи; это не гарантирует, что они действительно записаны на физическое устройство, такое как дисковый накопитель.


**Scanner

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

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



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


  • Токен - это подстрока, не содержащая разделителей и ограниченная слева и справа разделителями. Стандартными разделителями являются: пробел ' ', символ табуляции '\t', перевода строки '\n' и возврата каретки '\r'.



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

  • BufferedReader работает синхронно, а Scanner — нет. BufferedReader следует использовать, если мы работаем с несколькими потоками.

  • BufferedReader имеет значительно большую буферную память, чем Scanner.

  • Сканер имеет небольшой буфер (1KB буфер символов) в отличие от BufferedReader (8KB байтовый буфер), но этого более чем достаточно.

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

  • При использовании BufferReader нужно указывать IO Exception.


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

У сканнера есть бафер, его размер 1KB (Буфер символов)

**Файл

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

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

  • Абсолютным путём, потому что он начинается с корня ФС.

  • Относительные пути — это пути, ведущие отсчёт от какого-то каталога. 


2. Методы File

boolean createNewFile() создает новый файл

boolean delete() удаляет файл

boolean exists() проверяет есть ли каталог или файл

String getAbsolutePath() возвращает путь

getName() имя

getParent() имя род класса

isDirectory() если есть каталог, тру

isFile() если находится файл, тру

isHidden() если файл скрытый, тру

length() размер файла в байтах

lastModified() время изменения

list() возвращает массив файлов и катологов

listFiles() возвращает массив файлов и подкатологов

mkdir() создает каталог

renameTo(File dest) переименовывает
3. Как создать файл на компьютере с помощью java.

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



Создать файл в Java можно одним из трех способов, передав в объект File:

  • абсолютный путь

  • только указать имя файла

  • указать относительный путь (в этом случае объект файла пытается найти файлы в корневой директории проекта)




  • Создайте файл с классом java.io.FileOutputStream


Если вы хотите создать новый файл и в то же время, если хотите записать в него некоторые данные, вы можете использовать метод записи FileOutputStream.

Источник: https://java-blog.ru/osnovy/kak-sozdat-fayl-java


  • Создайте файл с помощью Java.nio.file.Files – Java NIO

Files.write()


  • Создание временного файла с использованием java.io.File.createTempFile()



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

  • Для удаления файлов или папок в Java используется метод  java.io.File delete(). Он возвращает true, если файл удалился успешно и возвращает false, если указанный для удаления файл не существует или не может быть удален. Если вы пытаетесь удалить папку, то этот метод проверяет указанную папку на пустоту. Если папка пуста, то она удаляется, если в папке что-то есть, то метод delete() просто возвращает false, то есть папка не удаляется.



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

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

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

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

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


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

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

Клонирование  это процесс создания копии объекта. Класс объектов Java поставляется с собственным clone () методом, который возвращает копию существующего экземпляра.


  • В первую очередь необходимо реализовать интерфейс Cloneable. Если этого не сделать, при вызове метода clone() выбросится исключение CloneNotSupportedException. (Интерфейс Cloneable является маркерным, то есть не имеет ни одного метода.) Он показывает что объекты класса могут быть клонированы. Метод clone() является protected, поэтому класс может клонировать только собственные объекты. Для того, чтобы клонировать другие объекты, метод clone() нужно расширить до public.

Пример клонирования:

public User clone() {

return (User) super.clone();

}
2. Клонирование объекта. Глубокое и поверхностное.
Поверхностное копирование копирует настолько малую часть информации, насколько это возможно. По умолчанию, клонирование в Java является поверхностным, т.е. Object class не знает о структуре класса, которого он копирует. При клонировании, JVM делает такие вещи:

  1. Если класс имеет только члены примитивных типов, то будет создана совершенно новая копия объекта и возвращена ссылка на этот объект.

  2. Если класс содержит не только члены примитивных типов, а и любого другого типа класса, тогда копируются ссылки на объекты этих классов. Следовательно, оба объекта будут иметь одинаковые ссылки.

Глубокое копирование дублирует все. Глубокое копирование — это две коллекции, в одну из которых дублируются все элементы оригинальной коллекции. Мы хотим сделать копию, при которой внесение изменений в любой элемент копии не затронет оригинальную коллекцию. Глубокое клонирование требует выполнения следующих правил:

  1. Нет необходимости копировать отдельно примитивные данные;

  2. Все классы-члены в оригинальном классе должны поддерживать клонирование. Для каждого члена класса должен вызываться super.clone() при переопределении метода clone();

  3. Если какой-либо член класса не поддерживает клонирование, то в методе клонирования необходимо создать новый экземпляр этого класса и скопировать каждый его член со всеми атрибутами в новый объект класса, по одному.


Различают два типа клонирования: поверхностное (shallow) и глубокое (deep). При поверхностном клонировании копируется сам объект. Все значимые поля клона получают значения, совпадающие со значениями полей объекта; все ссылочные поля клона являются ссылками на те же объекты, на которые ссылается и сам объект. При глубоком клонировании копируется вся совокупность объектов, связанных взаимными ссылками. 
3. Чем отличается копирование от клонирования.

  • clone-создайте что-то новое на основе чего-то существующего.

  • При копировании объектов, мы создаем не новый объект, а объект, который ссылается на копируемый




  • copy: копировать существующий экземпляр (неглубокий или глубокий)

  • clone: копировать в новый экземпляр (всегда глубоко)


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

  • Строку нет, массив можно


5. Какое клонирование в Java по умолчанию?

Поверхностное
**Сериализация

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

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

  • десериализация это процесс восстановления объекта, из этих байт


2. Назовите несколько форматов сериализации.

  • 1. JSON

  • JavaScript Object Notation

  • 2. XML (Каждый элемент состоит из открывающего и закрывающего тега (<> и ))

  • 3. BinarySON - тот же JSON только в двоичном представлении.

  • 4. YAML - Yet Another Markup Language



3. Как сериализовать объект класса.
1) Класс объекта должен реализовывать интерфейс Serializable

2) Создать поток ObjectOutputStream (oos), который записывает объект в переданный OutputStream.

3) Записать в поток: oos.writeObject(Object);

4) Сделать oos.flush() и oos.close()

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

  • Это поле нужно пометить ключевым словом transient.


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

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


6. Externalizable vs Serializable

  • Производительность. Интерфейс Serializable имеет много плюсов (простота, удобство), но производительность не из их числа.

  • Гибкость. Serializable вообще не позволяет управлять процессом, кроме исключения полей или добавление (через свою реализацию методов writeObject/readObject).

  • Безопасность. Externalizable более безопасный. Иногда необходимо шифрование данных.



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

  1. Помечать нужные поля этой аннотацией @Expose

  2. Помечать игнорируемые поля этой аннотацией

  3. Использовать модификатор transient вместо аннотаций



Когда мы пытаемся провести десериализацию, то есть восстановить объект из набора байт, значение serialVersionUID сравнивается со значением serialVersionUID класса в нашей программе. Если значения не совпадают, будет выброшено исключение java.io.InvalidClassException.
8. Что будет если перед десериализацией изменится класс, почему будет выброшено исключение.

  • Когда мы пытаемся провести десериализацию, то есть восстановить объект из набора байт, значение serialVersionUID сравнивается со значением serialVersionUID класса в нашей программе. Если значения не совпадают, будет выброшено исключение java.io.InvalidClassException.


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

  • код скомпилируется

  • в процессе выполнения вылетит исключение NotSerializableException.



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

  • Поля с модификатором final сериализуются как и обычные. За одним исключением - их невозможно десериализовать при использовании Externalizable, поскольку final-поля должны быть инициализированы в конструкторе, а после этого в readExternal изменить значение этого поля будет невозможно. Соответственно, если необходимо сериализовать объект с final-полем необходимо использовать только Serializable.


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

  • Помеченные ключевым словом transient, статические.


12. Выполнится ли flush если мы сделаем close у потока?

да

14. Что такое канонический путь?

абсолютный
15. Какие объекты можно сериализовать?
Сериализовать можно только те объекты, которые реализуют интерфейс Serializable. Этот интерфейс не определяет никаких методов, просто он служит указателем системе, что объект, реализующий его, может быть сериализован. Сериализация. Класс ObjectOutputStream.


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

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

  • IO

1) Блокирующий ввод-вывод

Потоки ввода/вывода (streams) в Java IO являются блокирующими. Это значит, что когда в потоке выполнения (tread) вызывается read() или write() метод любого класса из пакета java.io.*, происходит блокировка до тех пор, пока данные не будут считаны или записаны. Поток выполнения в данный момент не может делать ничего другого.

2) Потокоориентированный ввод-вывод.

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


  • NIO

1) Неблокирующий ввод-вывод

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

2) Буфероориентированный ввод-вывод. Данные считываются в буфер для последующей обработки. Вы можете двигаться по буферу вперед и назад. Это дает немного больше гибкости при обработке данных.

3) Селекторы

Селектор Java NIO – это компонент, который может проверять один или несколько экземпляров Java NIO Channel и определять, какие каналы готовы, например, для чтения или записи. Таким образом, один поток может управлять несколькими каналами и, следовательно, несколькими сетевыми подключениями.
Класс Reader  это полный аналог класса InputStream, с одним только отличием: он работает с символами  char, а не с байтами. 
2. Что такое System.in, что такое System.out.

  • Переменная System.out ссылается на поток вывода. По умолчанию это консоль

  • Переменная System.in ссылается на поток ввода, которым по умолчанию является клавиатура



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

OutputStream реализует интерфейсы: Closeable, Flushable, AutoCloseable

Reader реализует интерфейсы: Closeable, AutoCloseable, Readable

Writer реализует интерфейсы: Closeable, Flushable, Appendable, AutoCloseable

Потоки делятся по типу данных: работают с байтами или работают с символами.

Таблица:


  • Если объект реализует интерфейс OutputStream, значит, он поддерживает последовательную запись в него байт (byte).

  • Если объект реализует интерфейс Reader, значит, он поддерживает последовательное чтение из него символов (char).

  • Если объект реализует интерфейс Writer, значит, он поддерживает последовательную запись в него символов (char). Поток вывода напоминает принтер. На принтер мы можем выводить документы.


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


  • Адаптер — это структурный паттерн, который позволяет подружить несовместимые объекты.



Паттерн Адаптер (Adapter), также известный как Обертка (Wrapper), является структурным (Structural) паттерном проектирования. Его цель преобразовать интерфейс класса в другой интерфейс, который ожидают клиенты. Адаптер позволяет классам работать вместе, что иначе невозможно из-за несовместимых интерфейсов.
5. Пример адаптера и декоратора из IO.
Адаптер — это структурный паттерн, который позволяет подружить
Пример из IO

public class BufferedReader extends Reader {… } public class InputStreamReader extends Reader {… }

  • java.io.InputStreamReader(InputStream) (возвращает объект Reader)

  • java.io.OutputStreamWriter(OutputStream) (возвращает объект Writer)


Декоратор это структурный паттерн, который позволяет добавлять объектам новые поведения на лету, помещая их в объекты-обёртки.
Все подклассы java.io.InputStream, OutputStream, Reader и Writer имеют конструктор, принимающий объекты этих же классов.
6. Thread и Runnable, что выбрать? Зачем нужно два вида реализации многопоточности?

Потоки – это распределение данных между собой.
Thread - это класс, некоторая надстройка над физическим потоком.

Runnable - это интерфейс, представляющий абстракцию над выполняемой задачей.

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

Runnable лучше реализовывать если вы хотите унаследоваться от другого класса.


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