ревью 4(done). Разница в io при работе с файлом и директорией. Что делает метод available()
Скачать 397.34 Kb.
|
Разница в IO при работе с файлом и директорией. Что делает метод available()? Что возвращает метод read()? Почему? Что вернет, если считает -1? Что возвращает перегруженый метод с массивом? Граница значения байта вообще и которые используются в IO? Что такое декоратор? Пример в IO Что такое паттерн адаптер? Что если я не хочу сериализовывать поле? Что если при десериализации поменять тип? Разница глубокого и поверхностного копирования. Как сделать глубокое при помощи метода clone() и без неё? Какие копии создаются методом clone() в Java по умолчанию? В каких случаях использовать reader и scanner? Конструкторы и методы класса File. Методы создания файлов. Абсолютный и относительный путь. Что такое Externalizable и для чего он нужен? Что будет если перед десериализцией изменится класс, почему будет выброшено исключение? BuferedReader и BuferedWriter, их методы и отличия от стримов. Почему важно закрывать потоки? В чём отличие File от Path? Особенность сериализации поля final? Какие интерфейсы реализует InputStream/ OutputStream/ Reader/ Writer? Thread и Runnable, что выбрать? Зачем нужно два вида реализации многопоточности? Какие потоки можно не закрывать (не вызывать метод close())? Что возвращает перегруженный read? Какаое максимальное значение вернет? Можно ли клонировать String Можно ли клонировать массив String Что будет при сериализации объекта у которого есть поле и оно не Serializable? Гарантируется ли запись данных в файл при вызове flush ? Что такое токен в Scanner? Три способа клонировать объект? Что в Java можно клонировать? Что такое System.in, что такое System.out? Отличие Scanner’a от BufferedReader’a? Расскажи про класс File? Как создать новый файл на жестком диске? Как удалить директорию с файлами? Что если в ней есть вложенные директории? Что делает метод read? Почему он возвращает int а не byte? Почему он не может возвращать byte? Что вернет метод read(), если он считывает файл и ему встречается байт равный -1? Как преобразовать считанные байты в символы? Какой класс для этого используется? Есть ли у сканера буфер? Что такое клонирование? Как реализовано клонирование в Java? Можно ли flush() для небуферизированного потока и что будет? Пример адаптера и декоратора из IO Чем отличается копирование от клонирования? Что делает flush? Выполнится ли flush если мы сделаем close у потока? Отличие пакета io от nio? Какие поля не сериализуются? Сериализация потомков сериализованных родителей. Особенность сериализации поля final ? Externalizable vs Serializable Как работает сам close()? Что и зачем нужно закрывать? Для чего класс File? Что и как можно создать? как можно удалять На каких паттернах основана иерархия потоков ввода/вывода. Знать и понимать реализацию Итак, базовая сущность файловой системы - это файл. Для работы с этой сущностью существует класс java.io.File. Этот класс представляет собой как простые файлы, так и директории (папки). Допустим, у нас есть папка "C:/temp" и мы хотим работать с файлом 1.bin в этой папке. Чтобы это сделать - нужно сначала создать объект класса File. Отмечу, что создание объекта класса File не создает файл непосредственно в файловой системе, речь идет лишь об объекте в памяти. .available() не блокирует поток выполнения при отсутствии данных , а .read() - блокирует. .available() возвращает примерное количество доступных для чтения байтов, а .read(byte[] b) - количество считанных в буфер (массив байтов), от -1 при достижении конца потока данных и до размера массива (b.length). .available() лишь проверяет наличие данных, а .read() - их считывает. Функция InputStream.read() возвращает считанный байт в интервале от 0 до 255 или -1 если считать его не представляется возможным. Итого 257 вариантов и тип byte их уже не охватывает. Если считает -1, то вернет 255, так как значение обрезается до 8 битов (Перегруженный)Возвращает количество байтов прочитанных в буффер, или -1 если в [] нет данных. Может принимать одно из 256 (от 0 до 255, но в джаве используется знаковый байт поэтому значения – -2^7 – 2^7-1). Байт в IO 0..255 Декоратор — это структурный паттерн, который позволяет добавлять объектам новые поведения на лету, помещая их в объекты-обёртки. inputstream, bytearrayinputstream, stringbuilderinputstreams и так далее являются основанными элементами. Filterinputstream - это базовый класс для классов декораторов. Фильтр входных потоков (например, bufferedinput stream) может выполнять дополнительные функции при чтении потоков или записи в них. Адаптер (Adapter) – это структурный паттерн, который позволяет адаптировать интерфейс класса в соответствии с требованиями системы. То есть, адаптер — это своеобразная прослойка между классами, приводящая интерфейс одного класса к используемому в другом. OutputStreamWriter мы легко «адаптирует» два интерфейса классов Writer и OutputStream друг другу. Класс InputStreamReader — это классический адаптер, он адаптирует InputStream и Reader Если добавить к полю ключевое слово transient – такое поле не сериализуется В таком случае будет выкинут InvalidClassException Поверхностное копирование копирует настолько малую часть информации, насколько это возможно. По умолчанию, клонирование в Java является поверхностным, т.е. Object class не знает о структуре класса, которого он копирует. При клонировании, JVM делает такие вещи: Если класс имеет только члены примитивных типов, то будет создана совершенно новая копия объекта и возвращена ссылка на этот объект. Если класс содержит не только члены примитивных типов, а и любого другого типа класса, тогда копируются ссылки на объекты этих классов. Следовательно, оба объекта будут иметь одинаковые ссылки. Глубокое клонирование требует выполнения следующих правил: Нет необходимости копировать отдельно примитивные данные; Все классы-члены в оригинальном классе должны поддерживать клонирование. Для каждого члена класса должен вызываться super.clone() при переопределении метода clone(); Если какой-либо член класса не поддерживает клонирование, то в методе клонирования необходимо создать новый экземпляр этого класса и скопировать каждый его член со всеми атрибутами в новый объект класса, по одному. Каждый класс в иерархии должен обязательно иметь свой переопределенный clone(), тогда большинство проблем можно решить просто используя super.clone(). Еще один вариант клонирования объекта - это конструктор копирования. Создается конструктор, принимающий на вход объект того же класса, который необходимо клонировать: Object.clone() по умолчанию выполняет поверхностную копию. Экземпляры класса java.io.BufferedReader предназначены для чтения потока символов с буферизацией (символов, массивов и строк). Экземпляры класса java.util.Scanner предназначены для разбора данных на составляющие с учетом форматов, шаблонов, разных разделителей. Входные данные для Scanner могут быть файлы, потоки байтов, потоки символов, строки. Использовать метод File.createNewFile(). Этот метод возвращает логическое значение Если вы хотите создать новый файл и в то же время, если хотите записать в него некоторые данные, вы можете использовать метод записи FileOutputStream. В Java FileOutputStream является классом потока байтов. Чтобы записать данные в файл, вы должны преобразовать данные в байты, а затем сохранить их в файл. Files.write() – лучший способ создать файл, и он должен быть вашим предпочтительным подходом в будущем, если вы его еще не используете. Это хороший вариант, потому что нам не нужно беспокоиться о закрытии ресурсов ввода-вывода. Создание временного файла в java может потребоваться во многих сценариях, но в основном это происходит во время модульных тестов, где вы не хотите сохранять результаты. Создание с помощью java.io.File.createTempFile() Полный или абсолютный путь — это путь, который указывает на одно и то же место в файловой системе, вне зависимости от текущего рабочего каталога или других обстоятельств. Полный путь всегда начинается с корневого каталога. Относительный путь представляет собой путь по отношению к текущему рабочему каталогу пользователя или активных приложений. Интерфейс Externalizable - это интерфейс, который позволяет вам определять пользовательские правила и собственный механизм для сериализации. Сериализация по умолчанию не защищает конфиденциальную информацию, такую как пароли и учетные данные, или что, если разработчики хотят обеспечить некоторую информацию во время процесса сериализации? Если мы изменим структуру нашего класса, например поля удаления / добавления, этот номер версии serialVersionUID также изменится, и в соответствии с JVM наш класс не будет совместим с версией класса сериализованного объекта. Вот почему мы получаем исключение InvalidClassException. JVM просто напросто не понимает как десериализовать сериализованный класс! BufferedReader/BufferedWriter - наследник Reader/Writer добавляющий методы чтения и записи целых строк, а не отдельных символов. буферизуя прочитанные символы, чтобы обеспечить эффективное считывание символов, массивов и строк. Можно указать в конструкторе вторым параметром размер буфера. InputStream/OutputStream - потоки читающие, пишущие байты. Читать и писать они могут все, т.к. все записано в байтах. Потоки – можно не закрывать, но затем, когда код из самостоятельной единицы превращается в часть кода другой, более мощной программы. Но Ваш код не освобождает ресурсы и в результате эти ресурсы "висят" невостребованными. Более того, Ваш код выполняется много раз и каждый раз открывает ресурс и не закрывает его. Такое поведение по меньшей мере приводит к напрасному расходу этих ресурсов, а в более глобальной перспективе замедляет работу не только программы, но и компьютера, на котором она выполняется. Path, по большому счету, — это переработанный аналог класса File. Работать с ним значительно проще, чем с File. Во-первых, из него убрали многие утилитные (статические) методы, и перенесли их в класс Files. Во-вторых, в Path были упорядочены возвращаемые значения методов. В классе File методы возвращали то String, то boolean, то File — разобраться было непросто. Например, был метод getParent(), который возвращал родительский путь для текущего файла в виде строки. Но при этом был метод getParentFile(), который возвращал то же самое, но в виде объекта File! Это явно избыточно. Поэтому в интерфейсе Path метод getParent() и другие методы работы с файлами возвращают просто объект Path. Никакой кучи вариантов — все легко и просто. Files(относится к NIO) Files — это утилитный класс, куда были вынесены статические методы из класса File. Files — это примерно то же, что и Arrays или Collections, только работает он с файлами, а не с массивами и коллекциями :) Он сосредоточен на управлении файлами и директориями. Используя статические методы Files, мы можем создавать, удалять и перемещать файлы и директории. В Java есть специальный класс (File), с помощью которого можно управлять файлами на диске компьютера – он устаревший, и весто него рекомендуется использовать Path. Поля с модификатором final сериализуются как и обычные. За одним исключением – их невозможно десериализовать при использовании Externalizable, поскольку final-поля должны быть инициализированы в конструкторе, а после этого в readExternal изменить значение этого поля будет невозможно. Соответственно, если необходимо сериализовать объект с final-полем неоходимо использовать только стандартную сериализацию. В классе Thread определены семь перегруженных конструкторов, большое количество методов, предназначенных для работы с потоками, и три константы (приоритеты выполнения потока). Метод run() выполняется при запуске потока. После определения объекта Runnable он передается в один из конструкторов класса Thread. Не нужно закрывать обычный Stream из Stream API. Не нужно закрывать тот поток, который объявлен в try-with-resources OutputStream – пустой метод close() Строки – неизменяемый объект, мы можем копировать их просто ссылаясь на них. Так как строки иммутабельны, клонировать их не обязательно (хотя можно). Хватит и клонировать только массив, а строки использовать те же При стандартной сериализации поля, имеющие модификатор static, не сериализуются. Соответственно, после десериализации это поле значения не меняет. При использовании реализации Externalizable сериализовать и десериализовать статическое поле можно, но не рекомендуется этого делать, т.к. это может сопровождаться трудноуловимыми ошибками. Поле с модификатором trainsent, будет равно null. flush (), очищает все потоки данных и полностью их записывает, а также дает новое пространство для новых потоков во временном расположении буфера. Но если буффер пустой (/ не попали данные через write) – то ничего записано не будет Токен (или маркер) представляет собой серию цифровых или буквенно-цифровых символов, которая заканчивается разделителем. Разделителем может быть символ табуляции, возврат каретки (перевод строки или же просто ‘Enter’), конец файла или пробел. Переопределение метода clone() и реализация интерфейса Cloneable(); Использование конструктора копирования; Использовать для клонирования механизм сериализации. Только объекты можно клонировать System.out/System.in – консольные потоки ввода вывода. Cканнер очень сильно проигрывает по быстродействию, он примерно в 1000 раз медленнее, чем BufferedReader. Но у сканнера уже впилены удобные функции по разбору текста на разные данные (целые числа, дробные числа, текст и тп), когда у bufferedreader-a их придется отдельно парсить. Итог - если данных мало, то удобнее сканнер, если много или важна быстрота - то однозначно bufferedreader Класс File, определенный в пакете java.io, не работает напрямую с потоками. Его задачей является управление информацией о файлах и каталогах. Хотя на уровне операционной системы файлы и каталоги отличаются, но в Java они описываются одним классом File. В зависимости от того, что должен представлять объект File - файл или каталог, мы можем использовать один из конструкторов для создания объекта: File(String путь_к_каталогу) File(String путь_к_каталогу, String имя_файла) File(File каталог, String имя_файла) Способы создания: Использовать метод File.createNewFile(). Этот метод возвращает логическое значение Если вы хотите создать новый файл и в то же время, если хотите записать в него некоторые данные, вы можете использовать метод записи FileOutputStream. В Java FileOutputStream является классом потока байтов. Чтобы записать данные в файл, вы должны преобразовать данные в байты, а затем сохранить их в файл. Создание временного файла в java может потребоваться во многих сценариях, но в основном это происходит во время модульных тестов, где вы не хотите сохранять результаты. Создание с помощью java.io.File.createTempFile() Java не может удалять папки с данными в нем. Вы должны удалить все файлы перед удалением папки. String[] entries = index.list(); for(String s: entries){ File currentFile = new File(index.getPath(),s); currentFile.delete(); } Тогда можно удалить папку с помощью index.delete() Он возвращает int, потому что, когда поток больше не может быть прочитан, он возвращает -1. Если он вернул байт, то -1 не может быть возвращен, чтобы указать на отсутствие входных данных, потому что -1 является допустимым байтом. Кроме того, вы не можете возвращать значение выше 127 или ниже -128, потому что Java обрабатывает только подписанные байты. Много раз, когда вы читаете файл, вам нужны неподписанные байты для вашего кода обработки. 255, так как обрезается до 8 битов System.out.println(Arrays.toString(bytes)); String str = new String(bytes,StandardCharsets.UTF_8); Либо используя Reader Сканер может читать текст с любого объекта, который реализует интерфейс Readable. Если вызов базового метода Readable.read (java.nio.CharBuffer), доступного для чтения, генерирует IOException, то сканер предполагает, что достигнут конец ввода. Похоже, что Scanner не имеет своего собственного буфера. Он использует буфер из базового объекта (который реализует Readable) и использует регулярные выражения для анализа. Клонирование — это процесс копирования объекта, то есть создания нового экземпляра путем копирования самого себя. Для реализации клонирования класс должен применить интерфейс Cloneable, который определяет метод clone. Реализация этого метода просто возвращает вызов метода clone для родительского класса - то есть класса Object с преобразованием к типу Person. Кроме того, на случай если класс не поддерживает клонирование, метод должен выбрасывать исключение CloneNotSupportedException, что определяется с помощью оператора throws. В джава есть поверхностное копирование и глубокое В переводе на русский означает, что flush() вызывает чистку буфера вызывая метод реализованный в самой ОС поверх которой работает JVM. При этом даже отсутствие буфера в самом потоке не означает, что не будет использоваться в качестве буфера кэш диска на уровне ОСи или даже ниже. Использование flush() – хороший тон поскольку, девелопер не знает есть ли буфер на уровне ОС Декоратор — это структурный паттерн, который позволяет добавлять объектам новые поведения на лету, помещая их в объекты-обёртки.inputstream, bytearrayinputstream, stringbuilderinputstreams и так далее являются основанными элементами. Filterinputstream - это базовый класс для классов декораторов. Фильтр входных потоков (например, bufferedinput stream) может выполнять дополнительные функции при чтении потоков или записи в них. Он реализует все те же методы, что и InputStream, который лежит в нём, но позволяет к ним добавить доп. функционал. Конкретно его используют для какой-либо модификации данных из InputStream (т.е. фильтрации). Адаптеры: OutputStreamWriter мы легко «адаптирует» два интерфейса классов Writer и OutputStream друг другу. Класс InputStreamReader — это классический адаптер, он адаптирует InputStream и Reader Клонирование – создает что-то новое на основе существующего. Копирование - копирование с чего-то существующего на что-то другое (что также уже существует). Если вы хотите, чтобы буфер был сброшен, да, вызовите flush() перед вызовом close(). Несмотря на все другие ответы на обратное (но, как указано в некоторых комментариях), реализация java.io.OutputStream::close() по умолчанию не вызывает flush() Java IO (input-output) является потокоориентированным Java NIO (new/non-blocking io) – буфер-ориентированным. Static (если не сделали нужный static метод) и transient Когда Serializable класс имеет цепочку родителей, пока эти родители тоже Serializable, десериализация объекта идет от родителя к наследнику, в обход конструктора. Вместо него вызываются методы readObject (readObjectNoData). Но как только встречается первый предок, не реализующий интерфейс Serializable, инициализация для него возвращается в нормальное русло – вместо readObject вызывается конструктор без аргументов. Если такого конструктора нет, или он объявлен private, исполнение выбросит InvalidClassException. При сериализации несериализуемые предки просто игнорируются. Если класс несериализуемый и не предоставляет достаточного доступа к своему логическому состоянию для наследников, правильно реализовать его наследника сериализуемым может быть невозможно. Соответственно, если необходимо сериализовать объект с final полем необходимо использовать только стандартную сериализацию. Так как их невозможно десериализовать при использовании Externalizable, поскольку final поля должны быть инициализированы в конструкторе, а после этого в readExternal() изменить значение этого поля будет невозможно. При записи Serializable класса весь контроль над сериализацией достается JVM. С помощью определения специальных методов можно кастомизировать его части. Метод readObject при этом обычно начинается с вызова стандартной части сериализации – ObjectInputStream.defaultReadObject(). Интерфейс Externalizable расширяет Serializable и добавляет методы записи и чтения writeExternal и readExternal. Входной и выходной потоки-аргументы в них представлены более абстрактно чем в специальных методах – интерфейсами ObjectInput и ObjectOutput. Этот интерфейс позволяет реализовать полностью свой механизм сериализации, стандартно запишется только идентификатор класса. Никакой автоматической работы с классом-родителем также не предусмотрено. Методы readObject и writeObject игнорируются. Ключевое слово transient эффекта на Externalizable не имеет. Externalizable объект в отличие от Serializable десерализуется не в обход конструктора, так что должен иметь конструктор без аргументов. Метод close () закрывает соединение между программой и открытым файлом, чтобы закрыть ресурсы которые не могут не может очистить garbage collector, так как он не знает какие ресурсы есть помимо JVM. Если вы не закроете файл, открытый для чтения он может быть заблокирован для записи. Если вы не закроете файл, открытый для записи - вы можете потерять часть последних записанных данных, которые ОС держит в буфере. Адаптер и декоратор: Декоратор также оборачивает некоторый класс и предоставляет такой же или расширенный интерфейс. Иногда декоратор называют "умным заместителем" (smart proxy). Т.е. декоратор может притворяться оригинальным классом и при этом расширять его функциональность. Адаптер также оборачивает некоторый класс, но при этом предоставляет другой интерфейс. Т.е. используется в случаях, когда есть класс с нужными данными и поведением, но с неподходящим интерфейсом. Если вам нужно сериализовать статические поля, вы должны делать это вручную. (Создать статический метод, которые сериализует статическое поле) |