almost done 05abstract

This commit is contained in:
Ivan I. Ovchinnikov 2023-01-10 21:48:56 +03:00
parent 1b865320a6
commit 04aa8c0a9d
7 changed files with 728 additions and 324 deletions

Binary file not shown.

BIN
build/jtc5-05a.pdf Normal file

Binary file not shown.

View File

@ -125,19 +125,19 @@ GREEN(#00FF00)
\subsubsection{Задания для самопроверки}
\begin{enumerate}
\item Перечисления нужны, чтобы: 3
\item Перечисления нужны, чтобы:
\begin{enumerate}
\item вести учёт созданных в программе объектов;
\item вести учёт классов в программе;
\item вести учёт схожих по смыслу явлений в программе;
\end{enumerate}
\item Перечисление -- это: 2
\item Перечисление -- это:
\begin{enumerate}
\item массив
\item класс
\item объект
\end{enumerate}
\item каждый объект в перечислении -- это: 3
\item каждый объект в перечислении -- это:
\begin{enumerate}
\item статическое поле
\item статический метод
@ -229,19 +229,19 @@ orange.squeezeJuice();
\subsubsection{Задания для самопроверки}
\begin{enumerate}
\item Внутренний класс: 1
\item Внутренний класс:
\begin{enumerate}
\item реализует композицию;
\item это служебный класс;
\item не требует объекта внешнего класса;
\end{enumerate}
\item Инкапсуляция с использованием внутренних классов: 2
\item Инкапсуляция с использованием внутренних классов:
\begin{enumerate}
\item остаётся неизменной
\item увеличивается
\item уменьшается
\end{enumerate}
\item Статические поля внутренних классов: 2
\item Статические поля внутренних классов:
\begin{enumerate}
\item могут существовать
\item могут существовать только константными
@ -328,13 +328,13 @@ voice.sayMur();
\subsubsection{Задания для самопроверки}
\begin{enumerate}
\item Вложенный класс: 1
\item Вложенный класс:
\begin{enumerate}
\item реализует композицию;
\item это локальный класс;
\item всегда публичный;
\end{enumerate}
\item Статический вложенный классо бладает теми же свойствами, что: 2
\item Статический вложенный класс обладает теми же свойствами, что:
\begin{enumerate}
\item константный метод
\item внутренний класс
@ -530,6 +530,28 @@ throws IOException,
и, через запятую, все остальные возможные исключения этого метода. После этого, с ним не будет проблем исполнения, но у метода который его вызовет -- появилась необходимость обработать все checked исключения вызываемого. И так далее наверх.
\subsubsection{Задание для самопроверки}
\begin{enumerate}
\item Исключение -- это
\begin{enumerate}
\item событие в потоке исполнения;
\item объект, передаваемый от потока обработчику;
\item и то и другое верно.
\end{enumerate}
\item Обработчик исключений -- это объект, работающий
\begin{enumerate}
\item в специальном ресурсе
\item в специальном потоке
\item в специальный момент
\end{enumerate}
\item Стектрейс - это
\begin{enumerate}
\item часть потока выполнения программы;
\item часть объекта исключения;
\item часть информации в окне отладчика.
\end{enumerate}
\end{enumerate}
\subsubsection{Пример}
Для примера обработки исключений, возникающих на разных этапах работы приложения (жизненного цикла объекта) предлагается описать класс (листинг \hrf{lst:test-stream}), бизнес логика которого подразумевает создание, чтение некоторой информации, например, как если бы нужно было прочитать байт из файла, и закрытие потока чтения, то есть возврат файла обратно под управление ОС.

View File

@ -1,17 +1,669 @@
% Вот и настало время разобраться в тонкастях работы. На этом уроке мы начнём с файловой системы, как с ней взаимодействовать в целом, с файлами и каталогами. Мы узнаем как как управлять содержимым файлов, затем перейдём к разбору класса String, а так же разберёмся с сериализаторами и десериализаторами в Java.
\documentclass[j-spec.tex]{subfiles}
\begin{document}
\setcounter{section}{4}
\setlength{\columnsep}{22pt}
\pagestyle{plain}
\sloppy
\tableofcontents
\section{Специализация: тонкости работы}
\subsection{В предыдущем разделе}
Рассмотрены понятия внутренних и вложенных классов; процессы создания, использования и расширения перечислений. Подробно рассмотрены исключения с точки зрения ООП, их философия и тесная связь с многопоточностью в Java, обработка, разделение понятия штатных и нештатных ситуаций.
\subsection{В этом разделе}
Файловые системы и представление данных в запоминающих устройствах; Начало рассмотрения популярных пакетов ввода-вывода \code{java.io}, \code{java.nio}. Более подробно будет разобран один из самых популярных ссылочных типов данных \code{String} и механики вокруг него.
\begin{itemize}
\item \nom{Файл}{именованная область данных на носителе информации, используемая как базовый объект взаимодействия с данными в операционных системах.};
\item \nom{Загрузчик}{системное программное обеспечение, обеспечивающее загрузку операционной системы непосредственно после включения компьютера (процедуры POST) и начальной загрузки.};
\item \nom{Разделы}{(англ. partition), pаздел диска (англ. disk partition) -- часть долговременной памяти накопителя данных (жёсткого диска, SSD, USB-накопителя), логически выделенная для удобства работы, и состоящая из смежных блоков.};
\item \nom{BIOS}{(англ. basic input/output system -- «базовая система ввода-вывода») -- набор микропрограмм, реализующих низкоуровневые API для работы с аппаратным обеспечением компьютера, а также создающих необходимую программную среду для запуска операционной системы у IBM PC-совместимых компьютеров.};
\item \nom{ФС}{Файловая система (File System) -- один из ключевых компонентов всех операционных систем. В ее обязанности входит структуризация, чтение, хранение, запись файловой документации. Она напрямую влияет на физическое и логическое строение данных, особенности их формирования, управления, допустимый объем файла, количество символов в его названии и прочие.};
\item \nom{FAT}{(англ. File Allocation Table «таблица размещения файлов») -- классическая архитектура файловой системы, которая из-за своей простоты всё ещё широко применяется для флеш-накопителей.};
\item \nom{NTFS}{(аббревиатура от англ. new technology file system -- «файловая система новой технологии») -- стандартная файловая система для семейства операционных систем Windows NT фирмы Microsoft.};
\item \nom{Ввод-вывод}{взаимодействие между обработчиком информации (например, компьютер) и внешним миром, который может представлять как человек (субъект), так и любая другая система обработки информации};
\item \nom{Потоки в-в}{объекты, из которых можно считать данные и в которые можно записывать данные};
\item \nom{Строка}{ряд знаков, написанных или напечатанных в одну линию. Строка может также означать строковый тип данных в программировании.};
\item \nom{String}{Класс в Java, предназначенный для работы со строками. Все строковые литералы, определенные в Java программе -- это экземпляры класса String};
\end{itemize}
\subsection{Файловая система}
Повествование вплотную подошло к работе языка в части общения программы со внешним миром, а делать это не разобравшись в тонкостях работы файловой системы не эффективно. В этом подразделе находится материал, напрямую не относящийся к Java.
\begin{frm} \info Файловая система (File System) -- FS, ФС -- один из ключевых компонентов всех операционных систем. В ее обязанности входит структуризация, чтение, хранение, запись файловой документации. Она напрямую влияет на физическое и логическое строение данных, особенности их формирования, управления, допустимый объем файла, количество символов в его названии и прочие.
\end{frm}
\subsubsection{MBR, GPT}
ОС Linux, например, предоставляет возможность разбивки жесткого диска компьютера на отдельные разделы. Пользователи могут определить их границы по так называемым таблицам разделов. \textbf{Основная загрузочная запись (MBR)} и \textbf{таблица разделов GUID (GPT)} -- это два стиля формата разделов, которые позволяют компьютеру загружать операционную систему с жесткого диска, а также индексировать и упорядочивать данные.
Основная загрузочная запись (MBR) -- устаревшая форма разделения загрузочного сектора, первый сектор диска, который содержит информацию о том, как разбит диск. Он также содержит загрузчик, который сообщает компьютеру, как загрузить ОС. Main Boot Record состоит из трех частей:
\begin{itemize}
\item Основной загрузчик -- MBR резервирует первые байты дискового пространства для основного загрузчика. Windows размещает здесь очень упрощенный загрузчик, в то время как другие ОС могут размещать более сложные многоступенчатые загрузчики.
\item Таблица разделов диска -- таблица разделов диска находится в нулевом цилиндре, нулевой головке и первом секторе жёсткого диска. Она хранит информацию о том, как разбит диск. MBR выделяет 16 байт данных для каждой записи раздела и может выделить всего 64 байта. Таким образом, Main Boot Record может адресовать не более четырёх основных разделов или трёх основных раздела и один расширенный раздел.
\item Конечная подпись -- это 2-байтовая подпись, которая отмечает конец MBR. Всегда устанавливается в шестнадцатеричное значение \code{0x55AA}.
\end{itemize}
\begin{frm} \info Вообще, программисты любят всякие шестнадцатеричные подписи вроде \code{0xDEADBEEF}, \code{0xA11F0DAD}, \code{0xDEADFA11}, одну из таких подписей можно было увидеть в первом разделе, \code{0xcafebabe}. Они называются hexspeak.
\end{frm}
Таблица разделов GUID (GPT) -- это стиль формата раздела, который был представлен в рамках инициативы United Extensible Firmware Interface (UEFI). GPT был разработан для архитектурного решения некоторых ограничений MBR. Стиль GPT новее, гибче и надежнее, чем MBR. GPT использует логическую адресацию блоков для указания блоков данных. Первый блок помечен как LBA0, затем LBA1, LBA2, и так далее GPT хранит защитную запись MBR в LBA0, свой основной заголовок в логическом блоке и записи разделов в блоках со второго по тридцать третий.
GPT:
\begin{itemize}
\item Защитная MBR;
\item Основной тег GPT;
\item Записи разделов;
\item Дополнительный GPT.
\item Максимальная емкость раздела 9.4ZB;
\item 128 первичных разделов;
\item Устойчив к повреждению первичного раздела, так как имеет вторичный GPT;
\item Возможность использовать функции UEFI.
\end{itemize}
\textbf{Файловая система} -- это архитектура хранения информации, размещенной на жестком диске и в оперативной памяти. С её помощью пользователь получает доступ к структуре ядра системы.
На что влияет файловая система?
\begin{enumerate}
\item скорость обработки данных;
\item сбережение файлов;
\item оперативность записи;
\item допустимый размер блока;
\item возможность хранения информации в оперативной памяти;
\item способы корректировки пользователями ядра
\item и пр.
\end{enumerate} .
\subsubsection{Linux}
ОС Linux предоставляет возможность устанавливать в каждый отдельный блок свою файловую систему, которая и будет обеспечивать порядок поступающих и хранящихся данных, поможет с их организацией. Каждая ФС работает на наборе правил. Исходя из этого и определяется в каком месте и каким образом будет выполняться хранение информации. Эти правила лежат в основе иерархии системы, то есть всего корневого каталога. От того, насколько правильно администратор компьютера выберет тип файловой системы для каждого раздела, зависит ряд параметров, таких как: оперативность записи, скорость обработки данных, сбережение файлов, допустимый размер блока, возможность хранения информации в оперативной памяти и другие.
В файловой системе, хранятся файлы. Файлы в Linux -- это особенная отдельная категория данных. С точки зрения ОС -- всё файл. Все файлы делятся на категории.
\begin{itemize}
\item Regular File -- Предназначены для хранения двоичной и символьной информации. Это жесткая ссылка, ведущая на фактическую информацию, размещенную в каталоге. Если этой ссылке присвоить уникальное имя, получим Named Pipe, то есть именованный канал.
\item Device File -- файлы для устройств, туннелей. Речь идет о физических устройствах, представленных в ОС файлами. Могут классифицировать специальные символы и блоки. Обеспечивают мгновенный доступ к дисководам, принтерам, модемам, воспринимая их как простой файл с данными.
\item Soft Link -- мягкая (символьная) ссылка. Отвечает за мгновенный доступ к файлам, размещенным на любых носителях информации. В процессе копирования, перемещения и других действий пользователя, работающего по ссылке, будет выполняться операция над документом, на который ссылаются.
\item Directories -- Каталоги. Обеспечивают быстрый и удобный доступ к каталогам. Представляет собой файл с директориями и указателями на них. Это некого рода картотека: в папках размещаются документы, а в директориях дополнительные каталоги.
\item Block devices and sockets -- Блочные и символьные устройства. Выделяют интерфейс, необходимый для взаимодействия приложений с аппаратной составляющей. Каналы и сокеты. Отвечают за взаимодействие внутренних процессов в операционной системе.
\end{itemize}
\subsubsection{Windows}
Линейка файловых систем для Windows: какую роль они играют в работе системы и как они развивались.
\textbf{FAT(16) File Allocation Table}
Использовалась для MS-DOS 3.0, Windows 3.x, Windows 95, Windows 98, Windows NT/2000. Была разработана достаточно давно и предназначалась для работы с небольшими дисковыми и файловыми объемами, простой структурой каталогов. Таблица размещается в начале тома, причем хранятся две ее копии (в целях обеспечения большей устойчивости). Данная таблица используется операционной системой для поиска файла и определения его физического расположения на жестком диске. В случае повреждения и таблицы и ее копии чтение файлов операционной системой становится невозможно.
\textbf{Файловая система FAT32}
\begin{itemize}
\item возможность перемещения корневого каталога
\item возможность хранения резервных копий
\end{itemize}
Начиная с Windows 95, компания Microsoft начинает активно использовать в своих операционных системах FAT32 -- тридцатидвухразрядную версию FAT. FAT32 стала обеспечивать более оптимальный доступ к дискам, более высокую скорость выполнения операций ввода/вывода, а также поддержку больших файловых объемов (объем диска до 2 Тбайт).
\textbf{Файловая система NTFS} -- (от англ. New Technology File System), файловая система новой технологии
\begin{itemize}
\item права доступа
\item Шифрование данных
\item Дисковые квоты
\item Хранение разреженных файлов
\item Журналирование
\end{itemize}
Ни одна из версий FAT не обеспечивает хоть сколько-нибудь приемлемого уровня безопасности. Это, а также необходимость в добавочных файловых механизмах (сжатия, шифрования) привело к необходимости создания принципиально новой файловой системы. NTFS. В ней для файлов и папок могут быть назначены права доступа (на чтение, на запись и т.д.). Благодаря этому существенно повысилась безопасность данных и устойчивость работы системы. Одной из основных целей создания NTFS было обеспечение скоростного выполнения операций над файлами (копирование, чтение, удаление, запись), а также предоставление дополнительных возможностей: сжатие данных, восстановление поврежденных файлов системы на больших дисках и т.д. Другой основной целью создания NTFS была реализация повышенных требований безопасности.
Файловая система FAT для современных жестких дисков просто не подходит (ввиду ее ограниченных возможностей). Что касается FAT32, то ее еще можно использовать, но уже с оговорками.
\subsubsection{Файловые системы}
\begin{itemize}
\item Ext (extended) FS. Это расширенная файловая система, одна из первых. Была запущена в работу еще в 1992 году. В основе ее функциональности лежала ФС UNIX. Основная задача состояла в выходе за рамки конфигурации классической файловой системы MINIX, исключить ее ограничения и повысить эффективность администрирования. Сегодня она применяется крайне редко.
\item Ext2. Вторая, более расширенная вервия ФС, паявшаяся на рынке в 1993 году. По своей структуре продукт аналогичный Ext. Изменения коснулись интерфейса, конфигурации. Увеличился объем памяти, производительность. Максимально допустимый объем файлов для хранения (указывается в настройках) 2 ТБ. Ввиду невысокой перспективности применяется на практике редко.
\item Ext3. Третье поколение Extended FS, введенное в использование в 2001 году. Уже относится к журналируемой. Позволяет хранить логи изменения, обновления файлов данных записываются в отдельный журнал еще до того, как эти действия будут завершены. После перезагрузки ПК, такая ФС позволит восстановить файлы благодаря внедрению в систему специального алгоритма.
\item Ext4. Четвертое поколение Extended FS, запущенное в 2006 году. Здесь максимально убраны всевозможные ограничения, присутствующие в предыдущих версиях. Сегодня именно она по умолчанию входит в состав большей части дистрибутивов Линукс. Передовой ее нельзя назвать, но стабильность и надежность работы здесь в приоритете. В Unix системах применяется повсеместно.
\item JFS. Журналируемая система, первый аналог продуктам из основной группы, разработанная специалистами IBM под AIX UNIX. Отличается постоянством и незначительными требованиями к работе. Может использоваться на многопроцессорных ПК. Но в ее журнале сохраняются ссылки лишь на метаданные. Поэтому если произойдет сбой, автоматически подтянутся устаревшие версии данных.
\item ReiserFS. Создана Гансом Райзером исключительно под Линукс и названа в его честь. По своей структуре это продукт, похожий на Ext3, но с более расширенными возможностями. Пользователи могут соединять небольшие файлы в более масштабные блоки, исключая фрагментацию, повышая эффективность функционирования. Но в случае непредвиденного отключения электроэнергии есть вероятность потерять данные, которые будут группироваться в этот момент.
\item XFS. Еще один представитель группы журналируемых файловых систем. Отличительная особенность: в логи программа будет записывать только изменения в метаданных. Из преимуществ выделяют быстроту работы с объемной информацией, способность выделять место для хранения в отложенном режиме. Позволяет увеличивать размеры разделов, а вот уменьшать, удалять часть нельзя. Здесь также есть риск потери данных при отключении электроэнергии.
\item Btrfs. Отличается повышенной стойкостью к отказам и высокой производительностью. Удобная в работе, позволяет легко восстанавливать информацию, делать скриншоты. Размеры разделов можно менять в рабочем процессе. По умолчанию входит в OpenSUSE и SUSE Linux. Но обратная совместимость в ней нарушена, что усложняет поддержку.
\item F2FS. Разработка Самсунг. Уже входит в ядро Линукс. Предназначена для взаимодействия с хранилищем данных флеш-памяти. Имеет особую структуру: носитель разбивается на отдельные части, которые в свою очередь дополнительно еще делятся.
\item OpenZFS. Это ответ на вопрос какую файловую систему выбрать для Ubuntu она автоматически включена в поддержку ОС уже более 6 лет назад. Отличается высоким уровнем защиты от повреждения информации, автоматическим восстановлением, поддержкой больших объемов данных.
\item EncFS. Шифрует данные и пересохраняет их в этом формате в указанную пользователем директорию. Надо примонтировать ФС чтобы обеспечить доступ в расшифрованной информации.
\item Aufs. С ее помощью отдельные File Systems можно группировать в один раздел.
\item NFS. Позволит через сеть примонтировать ФС удаленного устройства.
\item Tmpfs. Предусмотрена возможность размещения пользовательских файлов непосредственно в оперативной памяти ПК. Предполагает создание блочного узла определенного размера с последующим подключением к папке. При необходимости данные можно будет удалять.
\item Procfs. По умолчанию размещена в папке proc. Буде содержать полный набор данных относительно процессов, запущенных в системе и непосредственно в ядре в режиме реального времени.
\item Sysfs. Такая ФС позволит пользователю задавать и отменять параметры ядра во время выполнения задачи.
\end{itemize}
\subsection{Файловая система и представление данных}
\subsubsection{File}
До появления Java 1.7 все операции проводились с помощью класса \code{File}.
В Java есть специальный класс (File), с помощью которого можно управлять файлами на диске компьютера. Для того чтобы управлять содержимым файлов, есть другие классы: \code{FileInputStream}, \code{FileOutputStream} и другие. Под управлением файлами понимается, что их можно создавать, удалять, переименовывать, узнавать их свойства и пр.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Создание объекта файла}]
File file = new File("file.txt");
\end{lstlisting}
Здесь происходит привычное создание объекта, причём в параметре конструктора задано так называемое относительное имя файла, то есть только имя и расширение, без указания полного пути, а значит файл будет открыт там, где исполняется программа.
С помощью объекта файла возможно работать и с директориями.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Использования файла для директории}]
File folder = new File(".");
for (File file : folder.listFiles())
System.out.println(file.getName());
\end{lstlisting}
Такой код выведет на экран всё содержимое \textit{текущей} директории, о чём говорит точка в строке с именем файла. Если просто указать имя файла, то будет использован файл в той же папке, что исполняемая программа, а если указана точка, то это означает использование непосредственно данной папки. метод \code{listFiles()} возвращает список файлов из указанной папки. А метод \code{getName()} выдаёт имя файла с расширением.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Методы класса \code{File}}]
System.out.println("Is it a folder - " + folder.isDirectory());
System.out.println("Is it a file - " + folder.isFile());
File file = new File("./Dockerfile");
System.out.println("Length file - " + file.length());
System.out.println("Absolute path - " + file.getAbsolutePath());
System.out.println("Total space on disk - " + folder.getTotalSpace());
System.out.println("File deleted - " + file.delete());
System.out.println("File exists - " + file.exists());
System.out.println("Free space on disk - " + folder.getFreeSpace());
\end{lstlisting}
Класс файл предоставляет ряд методов для манипуляции файлами и директориями.
\begin{itemize}
\item проверить, является ли объект файлом или директорией;
\item узнать размер файла в байтах и его абсолютный путь;
\item порядковый номер жёсткого диска, на котором расположен файл;
\item удалить файл (метод возвращает истину или ложь, как результат);
\item проверить, существует ли такой файл;
\item узнать, сколько ещё свободного места доступно на диске;
\item и другие.
\end{itemize}
\begin{frm} \info Фактически у класса \code{File} почти все методы дублированы: одна версия возвращает (и принимает в качестве параметра) \code{String}, вторая \code{File}.
\end{frm}
\subsubsection{Paths, Path, Files, FileSystem}
В Java 1.7 создатели языка решили изменить работу с файлами и каталогами.
У класса \code{File} существует ряд недостатков. Например, в нем нет метода \code{copy()}, который позволил бы скопировать файл. В классе \code{File} достаточно много методов, которые возвращают \code{boolean} значения.
Вместо единого класса \code{File} появились три класса: \code{Paths}, \code{Path} и \code{Files}. Также появился класс \code{FileSystem}, который предоставляет интерфейс к файловой системе.
\begin{frm} \excl
\begin{itemize}
\item [] \textbf{URI} -- Uniform Resource Identifier (унифицированный идентификатор ресурса);
\item [] \textbf{URL} -- Uniform Resource Locator (унифицированный определитель местонахождения ресурса);
\item [] \textbf{URN} -- Unifrorm Resource Name (унифицированное имя ресурса).
\end{itemize}
\end{frm}
\code{Paths} -- это совсем простой класс с единственным статическим методом \code{get()}. Его создали исключительно для того, чтобы из переданной строки или URI получить объект типа Path.
Фактически, \code{Path} -- это переработанный аналог класса \code{File}. Работать с ним значительно проще, чем с \code{File}. Например, метод \code{getParent()}, возвращает родительский путь для текущего файла в виде строки. Но при этом есть метод \code{getParentFile()}, который возвращал то же самое, но в виде объекта \code{File}. Это явно избыточно.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Использование классов \code{Path} и \code{Paths}}]
Path filePath = Paths.get("pics/logo.png");
Path fileName = filePath.getFileName();
System.out.println("Filename: " + fileName);
Path parent = filePath.getParent();
System.out.println("Parent directory: " + parent);
boolean endWithTxt = filePath.endsWith("logo.png");
System.out.println("Ends with filepath: " + endWithTxt);
endWithTxt = filePath.endsWith("png");
System.out.println("Ends with string: " + endWithTxt);
boolean startsWithPics = filePath.startsWith("pics");
System.out.println("Starts with filepath: " + startsWithPics);
\end{lstlisting}
\begin{frm} \excl В методы \code{startsWith()} и \code{endsWith()} нужно передавать путь, а не просто набор символов: в противном случае результатом всегда будет \code{false}, даже если текущий путь действительно заканчивается такой последовательностью символов.
\end{frm}
\begin{verbatim}
Filename: logo.png
Parent directory: pics
Ends with filepath: true
Ends with string: false
Starts with filepath: true
\end{verbatim}
Метод \code{normalize()} -- «нормализует» текущий путь, удаляя из него ненужные элементы.
\begin{frm} \info При обозначении путей часто используются символы \code{"."} (для обозначения текущей директории) и \code{".."} (для родительской директории).
\end{frm}
Если в программе появился путь, использующий \code{"."} или \code{".."}, метод \code{normalize()} позволит удалить их и получить путь, в котором они не будут содержаться.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Метод \code{normailze()}}]
Path path = Paths.get("./sources-draft/../pics/logo.png");
System.out.println(path.normalize());
\end{lstlisting}
\begin{verbatim}
pics/logo.png
\end{verbatim}
\code{Files} — это утилитарный класс, куда были вынесены статические методы из класса \code{File}. Он сосредоточен на управлении файлами и директориями.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Использование класса \code{Files}}]
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
Path file = Files.createFile(Paths.get("../pics/file.txt"));
System.out.print("Was the file captured successfully in pics directory? ");
System.out.println(Files.exists(Paths.get("../pics/file.txt")));
Path testDirectory = Files.createDirectory(Paths.get("./testing"));
System.out.print("Was the test directory created successfully? ");
System.out.println(Files.exists(Paths.get("./testing")));
file = Files.move(file, Paths.get("./testing/file.txt"), REPLACE_EXISTING);
System.out.print("Is our file still in the pics directory? ");
System.out.println(Files.exists(Paths.get("../pics/file.txt")));
System.out.print("Has our file been moved to testDirectory? ");
System.out.println(Files.exists(Paths.get("./testing/file.txt")));
Path copyFile = Files.copy(file, Paths.get("../pics/file.txt"), REPLACE_EXISTING);
System.out.print("Has our file been copied to pics directory? ");
System.out.println(Files.exists(Paths.get("../pics/file.txt")));
Files.delete(file);
System.out.print("Does the file exist in test directory? ");
System.out.println(Files.exists(Paths.get("./testing/file.txt")));
System.out.print("Does the test directory exist? ");
System.out.println(Files.exists(Paths.get("./testing")));
\end{lstlisting}
\begin{verbatim}
Was the file captured successfully in pics directory? true
Was the test directory created successfully? true
Is our file still in the pics directory? false
Has our file been moved to testDirectory? true
Has our file been copied to pics directory? true
Does the file exist in test directory? false
Does the test directory exist? true
\end{verbatim}
Класс Files позволяет не только управлять самими файлами, но и работать с его содержимым. Для записи данных в файл у него есть метод \code{write()}, а для чтения: \code{read()}, \code{readAllBytes()} и \code{readAllLines()}.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Использование класса \code{Files}}]
List<String> lines = Arrays.asList(
"The cat wants to play with you",
"But you don't want to play with it");
Path file = Files.createFile(Paths.get("cat.txt"));
if (Files.exists(file)) {
Files.write(file, lines, StandardCharsets.UTF_8);
lines = Files.readAllLines(
Paths.get("cat.txt"), StandardCharsets.UTF_8);
for (String s : lines) {
System.out.println(s);
}
}
\end{lstlisting}
\subsection{Потоки ввода-вывода, пакет \code{java.io}}
Подавляющее большинство программ обменивается данными со внешним миром. Это делают любые сетевые приложения -- они передают и получают информацию от других компьютеров и специальных устройств, подключенных к сети. Можно таким же образом представлять обмен данными между устройствами внутри одной машины. Программа может считывать данные с клавиатуры и записывать их в файл, или, наоборот - считывать данные из файла и выводить их на экран. Таким образом, устройства, откуда может производиться считывание информации, могут быть самыми разнообразными файл, клавиатура, входящее сетевое соединение и т.д. То же касается и устройств вывода это может быть файл, экран монитора, принтер, исходящее сетевое соединение и т.п. В конечном счете, все данные в компьютерной системе в процессе обработки передаются от устройств ввода к устройствам вывода.
Реализация системы ввода/вывода осложняется не только широким спектром источников и получателей данных, но еще и различными форматами передачи информации. Ею можно обмениваться в двоичном представлении, символьном или текстовом, с применением некоторой кодировки (кодировок только для русского языка их более 4 типов), или передавать числа в различных представлениях. Доступ к данным может потребоваться как последовательный, так и произвольный. Зачастую для повышения производительности применяется буферизация.
\begin{frm} \info В Java для описания работы по вводу/выводу используется специальное понятие потока данных (stream). Поток данных это абстракция, физически никакие потоки в компьютере никуда не текут.
\end{frm}
Поток связан с некоторым источником, или приемником, данных, способным получать или предоставлять информацию. Потоки делятся на входящие -- читающие данные и исходящие -- передающие (записывающие) данные. Введение концепции stream позволяет абстрагировать основную логику программы, обменивающейся информацией с любыми устройствами одинаковым образом, от низкоуровневых операций с такими устройствами ввода/вывода. Для программы нет разницы, передавать данные в файл или в сеть, принимать с клавиатуры или со специализированного устройства.
В Java потоки естественным образом представляются объектами. Описывающие их классы составляют основную часть пакета \code{java.io}. Все классы разделены на две части одни осуществляют ввод данных, другие вывод.
\subsubsection{Классы \code{InputStream} и \code{OutputStream}}
\begin{frm} \info Почти все классы пакета, осуществляющие ввод-вывод, так или иначе наследуются от InputStream для входных данных, и для выходных от OutputStream.
\end{frm}
\code{InputStream} -- это базовый абстрактный класс для потоков ввода, т.е. чтения.
\code{InputStream} описывает базовые методы для работы со входящими байтовыми потоками данных. Простейшая операция представлена методом \code{read()} (без аргументов). Согласно документации, этот метод предназначен для считывания ровно одного байта из потока, однако возвращает при этом значение типа \code{int}. В том случае, если считывание произошло успешно, возвращаемое значение лежит в диапазоне от 0 до 255 и представляет собой полученный байт (значение \code{int} содержит 4 байта и получается простым дополнением нулями в двоичном представлении). Если достигнут конец потока, то есть в нем больше нет информации для чтения, то возвращаемое значение равно -1. Если же считать из потока данные не удается из-за каких-то ошибок, или сбоев, будет брошено исключение \code{java.io.IOException}. Дело в том, что каналы передачи информации, будь то Internet или, например, жёсткий диск, могут давать сбои независимо от того, насколько хорошо написана программа. А это означает, что нужно быть готовым к ним, чтобы пользователь не потерял нужные данные. Когда работа с входным потоком данных окончена, его следует закрыть. Для этого вызывается метод \code{close()}. Этим вызовом будут освобождены все системные ресурсы, связанные с потоком.
\code{OutputStream} -- это базовый абстрактный класс для потоков вывода, т.е. записи.
В классе \code{OutputStream} аналогичным образом определяются три метода \code{write()} -- один принимающий в качестве параметра \code{int}, второй -- \code{byte[]} и третий -- \code{byte[]}, и два \code{int}-числа. Все эти методы ничего не возвращают. Для записи в поток сразу некоторого количества байт методу \code{write()} передается массив байт. Или, если мы хотим записать только часть массива, то передаем массив \code{byte[]} и два числа -- отступ и количество байт для записи. Реализация потока вывода может быть такой, что данные записываются не сразу, а хранятся некоторое время в памяти. Чтобы убедиться, что данные записаны в поток, а не хранятся в буфере, вызывается метод \code{flush()}. Когда работа с потоком закончена, его следует закрыть, для этого вызывается метод \code{close()}.
\begin{frm} \excl Закрытый поток не может выполнять операции вывода и не может быть открыт заново.
\end{frm}
\subsubsection{Классы \code{ByteArrayInputStream} и \code{ByteArrayOutputStream}}
Самый естественный для программы и простой для понимания источник, откуда можно считывать байты -- это, конечно, массив байт. Класс \code{ByteArrayInputStream} представляет собой поток, считывающий данные из массива байт. Этот класс имеет конструктор, которому в качестве параметра передается массив \code{byte[]}. Соответственно, при вызове методов \code{read()} возвращаемые данные будут браться именно из этого массива. Аналогично, для записи байт в массив применяется класс ByteArrayOutputStream. Этот класс использует внутри себя объект \code{byte[]}, куда записывает данные, передаваемые при вызове методов \code{write()}. Чтобы получить записанные в массив данные, вызывается метод \code{toByteArray()}. В примере будет создан массив, который состоит из трёх элементов: 1, -1 и 0. Затем, при вызове метода \code{read()} данные считывались из массива, переданного в конструктор \code{ByteArrayInputStream}. Обратите внимание, в данном примере второе считанное значение равно 255, а не -1, как можно было бы ожидать. Чтобы понять, почему это произошло, нужно вспомнить, что метод \code{read()} считывает \code{byte}, но возвращает значение \code{int}, полученное добавлением необходимого числа нулей (в двоичном представлении).
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Использование Byte Array Stream}]
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write(1);
out.write(-1);
out.write(0);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
int value = in.read();
System.out.println("First element is - " + value);
value = in.read();
System.out.println("Second element is - " + value +
". If (byte)value - " + (byte)value);
value = in.read();
System.out.println("Third element is - " + value);
\end{lstlisting}
\subsubsection{Классы \code{FileInputStream} и \code{FileOutputStream}}
Класс \code{FileInputStream} используется для чтения данных из файла. Конструктор такого класса в качестве параметра принимает название файла, из которого будет производиться считывание. При указании строки имени файла нужно учитывать, что она будет напрямую передана операционной системе, поэтому формат имени файла и пути к нему может различаться на разных платформах. Если при вызове этого конструктора передать строку, указывающую на несуществующий файл или каталог, то будет брошено \code{java.io.FileNotFoundException}. Если же объект успешно создан, то при вызове его методов \code{read()} возвращаемые значения будут считываться из указанного файла.
Для записи байт в файл используется класс \code{FileOutputStream}. При создании объектов этого класса, то есть при вызовах его конструкторов, кроме имени файла, также можно указать, будут ли данные дописываться в конец файла, либо файл будет полностью перезаписан.
\begin{frm} \excl Если не указан флаг добавления, то всегда сразу после создания \code{FileOutputStream} файл будет \textbf{создан} (содержимое существующего файла будет стёрто).
\end{frm}
При вызовах методов \code{write()} передаваемые значения будут записываться в этот файл. По окончании работы необходимо вызвать метод \code{close()}, чтобы сообщить системе, что работа по записи файла закончена.
\subsubsection{Другие потоковые классы}
\begin{itemize}
\item Классы \code{PipedInputStream} и \code{PipedOutputStream} характеризуются тем, что их объекты всегда используются в паре -- к одному объекту \code{PipedInputStream} привязывается (подключается) один объект \code{PipedOutputStream}. Они могут быть полезны, если в программе необходимо организовать обмен данными между модулями. Более явно выгода от использования проявляется при разработке многопоточных (multithread) приложений.
\item \code{StringBufferInputStream} (deprecated). Иногда бывает удобно работать с текстовой строкой как с потоком байт. Для этого возможно воспользоваться классом \code{StringBufferInputStream}. При создании объекта этого класса необходимо передать конструктору объект \code{String}.
\item Класс \code{SequenceInputStream} объединяет поток данных из других двух и более входных потоков. Данные будут вычитываться последовательно -- сначала все данные из первого потока в списке, затем из второго, и так далее. Конец потока \code{SequenceInputStream} будет достигнут только тогда, когда будет достигнут конец потока, последнего в списке.
\item FilterInputStream и FilterOutputStream и их наследники. Задачи, возникающие при вводе/выводе весьма разнообразны -- это может быть считывание байтов из файлов, объектов из файлов, объектов из массивов, буферизованное считывание строк из массивов и т.д. В такой ситуации решение с использованием простого наследования приводит к возникновению слишком большого числа подклассов. Более эффективно применение надстроек (в ООП этот шаблон называется адаптер). Надстройки -- наложение дополнительных объектов для получения новых свойств и функций. Таким образом, необходимо создать несколько дополнительных объектов -- адаптеров к классам ввода/вывода. В терминах \code{java.io} их называют фильтрами.
\item Класс \code{LineNumberInputStream} во время чтения данных производит подсчет, сколько строк было считано из потока. Номер строки, на которой в данный момент происходит чтение, можно узнать путем вызова метода \code{getLineNumber()}. Также можно и перейти к определенной строке вызовом метода \code{setLineNumber(int lineNumber)}. Этот класс практически разу объявили устаревшим и вместо него используется \code{LineNumberReader} с аналогичным функционалом.
\item \code{PushBackInputStream}. Этот фильтр позволяет вернуть во входной поток считанные из него данные. Такое действие производится вызовом метода \code{unread()}. Понятно, что обеспечивается подобная функциональность за счет наличия в классе специального буфера -- массива байт, который хранит считанную информацию.
\item PrintStream используется для конвертации и записи строк в байтовый поток. В нем определен метод \code{print()}, принимающий в качестве аргумента различные примитивные типы Java, а также тип \code{Object}. При вызове передаваемые данные будут сначала преобразованы в строку, после чего записаны в поток. Если возникает исключение, оно обрабатывается внутри метода \code{print()} и дальше не бросается (узнать, произошла ли ошибка, можно с помощью метода \code{checkError()}). Данный класс также считается устаревшим, и вместо него рекомендуется использовать \code{PrintWriter}, однако старый класс продолжает активно использоваться, поскольку статические поля \code{out} и \code{err} класса \code{System} имеют именно это тип.
\end{itemize}
\subsubsection{\code{BufferedInputStream} и \code{BufferedOutputStream}}
На практике при считывании с внешних устройств ввод данных почти всегда необходимо буферизировать. \code{BufferedInputStream} содержит массив байт, который служит буфером для считываемых данных. То есть, когда байты из потока считываются, либо пропускаются (методом \code{skip()}), сначала заполняется буферный массив, причём, из потока загружается сразу много байт, чтобы не требовалось обращаться к нему при каждой операции \code{read()} или \code{skip()}. \code{BufferedOutputStream} предоставляет возможность производить многократную запись небольших блоков данных без обращения к устройству вывода при записи каждого из них. Сначала данные записываются во внутренний буфер. Непосредственное обращение к устройству вывода и, соответственно, запись в него, произойдет, когда буфер заполнится. Инициировать передачу содержимого буфера на устройство вывода можно и явным образом, вызвав метод \code{flush()}. Для наглядности заполним небольшой файл данными, буквально 10 миллионов символов.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Сравнение простого и буферизующего потоков (шаг 1)}]
String fileName = "test.txt";
InputStream inStream = null;
OutputStream outStream = null;
try {
long timeStart = System.currentTimeMillis();
outStream = new BufferedOutputStream(new FileOutputStream(fileName));
for (int i = 1000000; --i >= 0;) { outStream.write(i); }
long time = System.currentTimeMillis() - timeStart;
System.out.println("Writing time: " + time + " millisec");
outStream.close();
} catch (IOException e) {
System.out.println("IOException: " + e.toString());
e.printStackTrace();
}
\end{lstlisting}
\begin{verbatim}
Writing time: 41 millisec
\end{verbatim}
На следующем шаге, прочитав эти символы из файла простым потоком ввода из файла, увидим, что это заняло сколько-то времени.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Сравнение простого и буферизующего потоков (шаг 2)}]
try {
long timeStart = System.currentTimeMillis();
InputStream inStream = new FileInputStream(fileName);
while (inStream.read() != -1) { }
long time = System.currentTimeMillis() - timeStart;
inStream.close();
System.out.println("Direct read time: " + (time) + " millisec");
} catch (IOException e) {
System.out.println("IOException: " + e.toString());
e.printStackTrace();
}
\end{lstlisting}
\begin{verbatim}
Direct read time: 2726 millisec
\end{verbatim}
На третьем шаге становится очевидно, что буферизующий поток справляется ровно с той-же задачей на пару порядков быстрее. Выгода использования налицо.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Сравнение простого и буферизующего потоков (шаг 3)}]
try {
long timeStart = System.currentTimeMillis();
inStream = new BufferedInputStream(new FileInputStream(fileName));
while (inStream.read() != -1) { }
long time = System.currentTimeMillis() - timeStart;
inStream.close();
System.out.println("Buffered read time: " + (time) + " millisec");
} catch (IOException e) {
System.out.println("IOException: " + e.toString());
e.printStackTrace();
}
\end{lstlisting}
\begin{verbatim}
Buffered read time: 23 millisec
\end{verbatim}
\subsubsection{Усложнение данных}
До сих пор речь шла только о считывании и записи в поток данных в виде \code{byte}. Для работы с другими типами данных Java определены интерфейсы \code{DataInput} и \code{DataOutput} и их реализации -- классы-фильтры \code{DataInputStream} и \code{DataOutputStream}, реализующие методы считывания и записи значений всех примитивных типов. При этом происходит конвертация этих данных в набор \code{byte} и обратно. Чтение необходимо организовать так, чтобы данные запрашивались в виде тех же типов, в той же последовательности, как и производилась запись. Если записать, например, \code{int} и \code{long}, а потом считывать их как \code{short}, чтение будет выполнено корректно, без исключительных ситуаций, но числа будут получены совсем другие.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Использование Data Stream (шаг 1)}]
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
DataOutputStream outData = new DataOutputStream(out);
outData.writeByte(128);
outData.writeInt(128);
outData.writeLong(128);
outData.writeDouble(128);
outData.close();
} catch (Exception e) {
System.out.println("Impossible IOException occurs: " + e.toString());
e.printStackTrace();
}
\end{lstlisting}
Далее прочитаем данные так, как они были записаны, все значения прочитаны корректно.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Использование Data Stream (шаг 2)}]
try {
byte[] bytes = out.toByteArray();
InputStream in = new ByteArrayInputStream(bytes);
DataInputStream inData = new DataInputStream(in);
System.out.println("Reading in the correct sequence: ");
System.out.println("readByte: " + inData.readByte());
System.out.println("readInt: " + inData.readInt());
System.out.println("readLong: " + inData.readLong());
System.out.println("readDouble: " + inData.readDouble());
inData.close();
} catch (Exception e) {
System.out.println("Impossible IOException occurs: " + e.toString());
e.printStackTrace();
}
\end{lstlisting}
\begin{verbatim}
Reading in the correct sequence:
readByte: -128
readInt: 128
readLong: 128
readDouble: 128.0
\end{verbatim}
Затем, всё ломаем и видим, что всё послушно сломалось.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Использование Data Stream (шаг 3)}]
try {
byte[] bytes = out.toByteArray();
InputStream in = new ByteArrayInputStream(bytes);
DataInputStream inData = new DataInputStream(in);
System.out.println("Reading in a modified sequence:");
System.out.println("readInt: " + inData.readInt());
System.out.println("readDouble: " + inData.readDouble());
System.out.println("readLong: " + inData.readLong());
inData.close();
} catch (Exception e) {
System.out.println("Impossible IOException occurs: " + e.toString());
e.printStackTrace();
}
\end{lstlisting}
\begin{verbatim}
Reading in a modified sequence:
readInt: -2147483648
readDouble: -0.0
readLong: -9205252085229027328
\end{verbatim}
Ещё сложнее \code{ObjectInputStream} и \code{ObjectOutputStream}. Для объектов процесс преобразования в последовательность байт и обратно организован несколько сложнее -- объекты имеют различную структуру, хранят ссылки на другие объекты и т.д. Поэтому такая процедура получила специальное название -- сериализация (serialization), обратное действие, -- то есть воссоздание объекта из последовательности байт -- десериализация.
\subsubsection{Классы Reader и Writer}
Рассмотренные классы -- наследники \code{InputStream} и \code{OutputStream} -- работают с байтовыми данными. Если с их помощью записывать или считывать текст, то сначала необходимо сопоставить каждому символу его числовой код. Такое соответствие называется кодировкой. Java предоставляет классы, практически полностью дублирующие байтовые потоки по функциональности, но называющиеся \code{Reader} и \code{Writer}, соответственно. Различия между байтовыми и символьными классами весьма незначительны. Классы-мосты \code{InputStreamReader} и \code{OutputStreamWriter} при преобразовании символов также используют некоторую кодировку.
\subsection{\code{java.nio} и \code{nio2}}
Основное отличие между двумя подходами к организации ввода/вывода в том, что Java IO является потокоориентированным, а Java NIO буфер-ориентированным.
\subsubsection{io vs nio}
Потокоориентированный ввод-вывод подразумевает чтение или запись из потока и в поток одного или нескольких байт в единицу времени поочередно. Таким образом, невозможно произвольно двигаться по потоку данных вперед или назад. Если есть необходимость произвести подобные манипуляции, придётся сначала кэшировать данные в буфере.
Подход, на котором основан Java NIO немного отличается. Данные считываются в буфер для последующей обработки. Становится возможно двигаться по буферу вперед и назад. Это дает больше гибкости при обработке данных. В то же время, появляется необходимость проверять содержит ли буфер необходимый для корректной обработки объем данных. Также необходимо следить, чтобы при чтении данных в буфер не были уничтожены ещё не обработанные данные, находящиеся в буфере.
Потоки ввода/вывода (streams) в Java IO являются блокирующими. Это значит, что когда в потоке выполнения вызывается \code{read()} или \code{write()} метод любого класса из пакета \code{java.io.*}, происходит блокировка до тех пор, пока данные не будут считаны или записаны. Поток выполнения (thread) в данный момент не может делать ничего другого. Неблокирующий режим Java NIO позволяет запрашивать считанные данные из канала (channel) и получать только то, что доступно на данный момент, или вообще ничего, если доступных данных пока нет.
\begin{frm} \info Каналы это логические порталы, через которые осуществляется ввод/вывод данных, а буферы являются источниками или приёмниками этих переданных данных. При организации вывода, данные, которые вы хотите отправить, помещаются в буфер, а он передается в канал. При вводе, данные из канала помещаются в предоставленный вами буфер.
\end{frm}
Также, в Java NIO появилась возможность создать поток, который будет знать, какой канал готов для записи и чтения данных и может обрабатывать этот конкретный канал. Данные считываются в буфер для последующей обработки.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Использование буфера и канала}]
try (RandomAccessFile catFile = new RandomAccessFile("cat.txt", "rw")) {
FileChannel inChannel = catFile.getChannel();
ByteBuffer buf = ByteBuffer.allocate(100);
int bytesRead = inChannel.read(buf);
while (bytesRead != -1) {
System.out.println("Read " + bytesRead + " bytes");
// Set read mode
buf.flip();
while (buf.hasRemaining()) {
System.out.print((char) buf.get());
}
buf.clear();
bytesRead = inChannel.read(buf);
}
} catch (IOException e) { e.printStackTrace(); }
\end{lstlisting}
Подготовив всё необходимое приложение прочитало данные в буфер, сохранив число прочитанных байт, а затем прочитанные байты посимвольно были выведены в консоль. Для чтения данных из файла используется файловый канал. Объект файлового канала может быть создан только вызовом метода \code{getChannel()} для файлового объекта, поскольку нельзя напрямую создать объект файлового канала. При этом, \code{FileChannel} нельзя переключить в неблокирующий режим.
\subsection{String}
Класс String отвечает за создание строк, состоящих из символов. Если быть точнее, заглянув в реализацию и посмотрев способ их хранения, то строки (до Java 9) представляют собой массив символов
\begin{lstlisting}[language=Java,style=JCodeStyle]
private final char value[];
\end{lstlisting}
а начиная с Java 9 строки хранятся как массив байт.
\begin{lstlisting}[language=Java,style=JCodeStyle]
private final byte[] value;
\end{lstlisting}
Данный материал в первую очередь направлен на Java 1.8. В отличие от других языков программирования, где символьные строки представлены последовательностью символов, в Java они являются объектами класса \code{String}. В результате создания объекта типа String получается неизменяемая символьная строка, т.е. невозможно изменить символы имеющейся строки. При любом изменении строки создается новый объект типа \code{String}, содержащий все изменения. А значит у String есть две фундаментальные особенности: это immutable (неизменный) класс; это final класс (у класса String не может быть наследников).
\begin{lstlisting}[language=Java,style=JCodeStyle]
import java.nio.charset.StandardCharsets;
String s1 = "Java";
String s2 = new String("Home");
String s3 = new String(new char[] { 'A', 'B', 'C' });
String s4 = new String(s3);
String s5 = new String(new byte[] { 65, 66, 67 });
String s6 = new String(new byte[] { 0, 65, 0, 66 }, StandardCharsets.UTF_16);
\end{lstlisting}
Экземпляр класса \code{String} можно создать множеством способов. Несмотря на кажущуюся простоту, класс строки -- это довольно сложная структура данных и огромный набор методов.
C помощью операции конкатенации, которая записывается, как знак \code{+}, можно соединять две символьные строки, порождая новый объект типа \code{String}. Операции такого сцепления символьных строк можно объединять в цепочку. Строки можно сцеплять с другими типами данных, например, целыми числами. Так происходит потому, что значение типа \code{int} автоматически преобразуется в своё строковое представление в объекте типа \code{String}.
\begin{frm} \excl Сцепляя разные типы данных с символьными строками, следует быть внимательным, иначе можно получить неожиданные результаты.
\begin{verbatim}
String s0 = "Fifty five is " + 50 + 5; // Fifty five is 505
String s1 = 50 + 5 + " = Fifty five"; // 55 = Fifty five
\end{verbatim}
Такой результат объясняется ассоциативностью оператора сложения. Оператор сложения «работает» слева направо, а расширение типа до максимального происходит автоматически, так если складывать целое и дробное, в результате будет дробное, если складывать любое число и строку получится строка. Однажды получив строку, дальнейшее сложение превратится в конкатенацию.
\end{frm}
\subsubsection{StringBuffer, StringBuilder}
Поскольку строка это достаточно неповоротливо, были придуманы классы, которые позволяют ускорить работу с ними.
Если в программе планируется работа со строками в больших циклах, следует рассмотреть возможность использования \code{StringBuilder}.
\begin{frm} \info Помните, что если что-то «тормозит», то с 90\% вероятностью уже придумали способ это ускорить. Все строковые классы работают с массивами символов, но \code{String} делает это примитивно, выделяя каждый раз новый блок памяти под массив с длиной равной длине строки, а \code{StringBuilder} сразу выделяет большой блок памяти под массив, добавляет к нему элементы по индексу, а если массив заканчивается, то тогда делает массив в два раза больше, копирует в него старый, и заполняет уже его.
\end{frm}
Разработчики Java знали, что перед программистами будут стоять задачки и посерьёзнее, чем обработка нескольких тысяч символьных строк, например, при разборе текстовых файлов, и поиске информации в электронных книгах. Поэтому придумали \code{StringBuilder} и \code{StringBuffer}. Создают они изменяемые строки и динамические ссылки на них. Их разница в том, что \code{StringBuilder} не потокобезопасный, и работает чуть быстрее, а \code{StringBuffer} -- используется в многопоточных средах, но в одном потоке работает чуть медленнее.
\begin{lstlisting}[language=Java,style=JCodeStyle]
String s = “Example”;
long timeStart = System.nanoTime();
for (int i = 0; i < 30000; ++i) {
s = s + i;
}
double deltaTime = (System.nanoTime() - timeStart) * 0.000000001;
System.out.println("Delta time: " + deltaTime);
StringBuilder sb = new StringBuilder("Example");
long timeStart = System.nanoTime();
for (int i = 0; i < 100_000; ++i) {
sb = sb.append(i);
}
double deltaTime = (System.nanoTime() - timeStart) * 0.000000001;
System.out.println("Delta time: " + deltaTime);
\end{lstlisting}
В конструктор передано начальное значение строки. То есть это всё ещё строка, но представленная другим классом
\subsubsection{String pool}
Экземпляр класса String хранится в памяти, именуемой куча (heap), но есть некоторые нюансы. Если строка, созданная при помощи конструктора хранится непосредственно в куче, то строка, созданная как строковый литерал, уже хранится в специальном месте кучи — в так называемом пуле строк (string pool). В нем сохраняются исключительно уникальные значения строковых литералов. Процесс помещения строк в пул называется интернирование (от англ. interning, внедрение, интернирование). Когда объявляется переменная типа \code{String} ей присваивается строковый литерал, то JVM обращается в пул строк и ищет там такое же значение. Если пул содержит необходимое значение, то компилятор просто возвращает ссылку на соответствующий адрес строки без выделения дополнительной памяти. Если значение не найдено, то новая строка будет интернирована, а ссылка на нее возвращена и присвоена переменной.
\begin{lstlisting}[language=Java,style=JCodeStyle]
String cat0 = "BestCat";
String cat1 = "BestCat";
String cat2 = "Best" + "Cat";
String cat30 = "Best";
String cat3 = cat30 + "Cat";
\end{lstlisting}
В строке «Best» + «Cat» создаются два строковых объекта со значениями «Best» и «Cat», которые помещаются в пул. «Склеенные» строки образуют еще одну строку со значением «BestCat», ссылка на которую берется из пула строк (а не создается заново), т.к. она была интернирована в него ранее. Значения всех строковых литералов из данного примера известно на этапе компиляции. А если предварительно поместить один из фрагментов строки в переменную, можно «запутать» пул строк и заставить его думать, что в результате получится совсем новая строка.
\begin{verbatim}
cat0 equal to cat1? true
cat0 equal to cat2? true
cat0 equal to cat3? false
\end{verbatim}
Когда создаётся экземпляр класса \code{String} с помощью оператора \code{new}, компилятор размещает строки в куче. При этом каждая строка, созданная таким способом, помещается в кучу (и имеет свою ссылку), даже если такое же значение уже есть в куче или в пуле строк. Это нерационально. В Java существует возможность вручную выполнить интернирование строки в пул путем вызова метода \code{intern()} у объекта типа \code{String}.
\begin{frm} \excl «Почему бы все строки сразу после их создания не добавлять в пул строк? Ведь это приведет к экономии памяти». Среди большого количества программистов присутствует такое заблуждение, поскольку не все учитывают дополнительные затраты виртуальной машины на процесс интернирования, а также падение производительности, связанное с аппаратными ограничениями памяти, ведь невозможно читать ячейку памяти одновременно бесконечным числом процессов.
\end{frm}
Можно сказать, что интернирование в виде применения метода \code{intern()} рекомендуется не использовать. Вместо интернирования необходимо использовать дедупликацию. Если коротко, во время сборки мусора Garbage Collector проверяет живые (имеющие рабочие ссылки) объекты в куче на возможность провести их дедупликацию. Ссылки на подходящие объекты вставляются в очередь для последующей обработки. Далее происходит попытка дедупликации каждого объекта \code{String} из очереди, а затем удаление из нее ссылок на объекты, на которые они ссылаются.
\subsection*{Практическое задание}
\begin{enumerate}
\item создать пару-тройку текстовых файлов. Для упрощения (не разбираться с кодировками) внутри файлов следует писать текст только латинскими буквами.
\item написать метод, осуществляющий конкатенацию переданных ей в качестве параметров файлов (не особо важно, в первый допишется второй или во второй первый, или файлы вовсе объединятся в какой-то третий);
\item написать метод поиска слова внутри файла.
\end{enumerate}
\newpage
\printnomenclature[40mm]
\end{document}
% Что такое файловая система.
% Перед тем, как приступить к изучению классов, которые работают с файловой системой, предлагаю разобраться вообще с понятием файловой системы, что она из себя представляет и как с ней взаимодействовать.
% Что же такое файловая система (File System) - FS, ФС один из ключевых компонентов всех операционных систем. В ее обязанности входит структуризация, чтение, хранение, запись файловой документации. Она напрямую влияет на физическое и логическое строение данных, особенности их формирования, управления, допустимый объем файла, количество символов в его названии и пр. В качестве примеров выступают две операционные системы Linux и Windows.
% В ядре ОС Линукс предусмотрен огромный набор заблаговременно установленных файловых систем. Их задача помогать пользователю в решении той или иной поставленной задачи. Для определенного раздела можно выбирать свою систему, ориентируясь на предстоящие потребности: обеспечение быстродействия, гарантированное восстановление информации, повышенная производительность. Речь идет как о стандартных, так и о специализированные либо же виртуальных файловых системах.
% В ОС Линукс еще на этапе установки пользователю предоставляется на выбор большое количество ФС, вмонтированных в ее ядро. Пользователь самостоятельно выбирает вариант, который будет соответствовать его запросам и проблемам, требующим решения в рабочем процессе. Обратите внимание: подобное актуально только для операционной системы Linux и Windows NT (с файловой системой новой технологии NTFS). Для обычного Windows не предусмотрено возможности выбора вида файловых систем. Отличными здесь будут и строение каталога, и иерархия самих ФС.
% ОС Линукс также предоставляет возможность разбивки жесткого диска персонального компьютера на отдельные разделы. Пользователи могут определить их границы по так называемым таблицам разделов GPT, MBR. Здесь указывается метка и номер директории, адрес его реального размещения: точки старта и финиша.
% Чуток подробнее рассмотрим данные форматы:
% Итак, допустим, вы получили новый SSD, подключили и зашли в «Управление дисками», чтобы его инициализировать.
% Утилита управления дисками спросит, хотите ли вы использовать стиль разделов MBR или GPT?
% Основная загрузочная запись (MBR) и таблица разделов GUID (GPT) — это два стиля формата разделов, которые позволяют вашему компьютеру загружать операционную систему с жесткого диска, а также индексировать и упорядочивать данные.
% Для большинства людей предпочтительным стилем разделов должен быть GPT — более новый из двух.
% Однако не всегда все бывает просто.
% Основная загрузочная запись (MBR)
% Основная загрузочная запись (MBR) — это устаревшая форма разделения загрузочного сектора. Это первый сектор диска, который содержит информацию о том, как разбит диск. Он также содержит загрузчик, который сообщает вашей машине, как загрузить ОС.
@ -22,23 +674,11 @@
% Конечная подпись.
% .tg {border-collapse:collapse;border-spacing:0;}
% .tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
% overflow:hidden;padding:10px 5px;word-break:normal;}
% .tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
% font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
% .tg .tg-0pky{border-color:inherit;text-align:center;vertical-align:center}
% Смещение
% Длина, байт
% Описание
% 0000h
% 446
% Код загрузчика
@ -70,43 +710,6 @@
% Сигнатура (55h AAh)
% Основной загрузчик
% MBR резервирует первые 446 байт дискового пространства для основного загрузчика.
% Windows размещает здесь очень упрощенный загрузчик, в то время как другие ОС могут размещать более сложные многоступенчатые загрузчики.
% Таблица разделов диска
% Таблица разделов диска находится в цилиндре 0, головке 0 и секторе 1 жесткого диска. Она хранит информацию о том, как разбит диск.
% MBR выделяет 16 байт данных для каждой записи раздела и может выделить всего 64 байта. Таким образом, MBR может адресовать не более 4 основных разделов или 3 основных раздела и 1 расширенный раздел. Расширенный раздел используется для создания нескольких логических разделов. Это полезно, когда пользователю нужно создать более 4 разделов. Однако операционная система может быть установлена только в основных разделах, а не в логических разделах.
% Конечная подпись
% 2-байтовая подпись отмечает конец MBR.
% Всегда устанавливается в шестнадцатеричное значение 0x55AA.
% Некоторые особенности основной загрузочной записи:
% Возможность инициализировать загрузчик в устаревшем режиме BIOS;
% Может адресовать до 2 ТБ дискового пространства;
% Может иметь 4 основных раздела или 3 основных раздела и 1 дополнительный раздел;
% Возможность загрузки Windows 7 и более ранних версий Windows.
% Плюсы:
% Совместимость со всеми версиями Windows, включая Windows 7 и более ранние версии;
% Требуется для обеспечения совместимости со старым 32-разрядным оборудованием;
% Использует 32-битные значения, поэтому имеет меньшие накладные расходы, чем GPT.
% Минусы:
% Максимальная емкость раздела составляет 2 ТБ;
% Ограничено 4 основными разделами или 3 основными разделами и 1 расширенным разделом;
% Не устойчив к повреждению MBR;
% Не имеет встроенного исправления ошибок для защиты данных, поскольку использует BIOS.
% Таблица разделов GUID (GPT)
% Таблица разделов GUID (GPT) — это стиль формата раздела, который был представлен в рамках инициативы United Extensible Firmware Interface (UEFI). GPT был разработан для архитектурного решения некоторых ограничений MBR.
% КАРТИНКА
@ -149,239 +752,6 @@
% Возможность использовать функции UEFI, такие как безопасная загрузка, быстрый запуск и т. д.
% MBR против GPT: различия
% Различия между MBR и GPT заключаются в следующем:
% 1. Требования к прошивке.
% Прошивка — это программное обеспечение, обеспечивающее низкоуровневое управление аппаратным устройством и встроенное в само устройство.
% Базовая система ввода-вывода (BIOS) и унифицированный расширенный интерфейс встроенного ПО (UEFI) — это две встроенные программы, которые сегодня широко распространены в компьютерах.
% BIOS является старым из двух и в настоящее время имеет устаревший статус.
% Для работы MBR требуется устаревшая прошивка BIOS, в то время как GPT, как часть спецификации UEFI, требует загрузки прошивки EFI.
% Теоретически возможна загрузка в некоторые ОС с дисками с разделами MBR в системах с прошивкой EFI. Однако Windows требует, чтобы диски были разбиты на разделы GPT для использования UEFI.
% Если ваш диск разбит на разделы MBR, Windows предоставляет инструмент «diskpart» для преобразования его в GPT без потери данных. Точно так же теоретически также возможно загрузить некоторые ОС на компьютере с устаревшей версией BIOS и дисками с разделами GPT.
% Однако Windows этого не позволяет.
% 2. Поддержка Windows
% Windows 7 и более ранние версии Windows, работающие на 32-разрядных компьютерах, совместимы только с дисками с разделами MBR.
% Windows 8 и более поздние версии могут использовать диски с разделами GPT и MBR.
% Это связано с тем, что Windows 7 и более ранние версии не поддерживают UEFI на 32-разрядных платформах и, следовательно, не разрешают загрузку с разделов GPT.
% 64-разрядные версии более ранних версий Windows могут читать и записывать с дисков с разделами GPT, но не могут загружаться с них.
% 3. Максимальная ёмкость раздела
% Максимальный размер диска, который может адресовать раздел MBR, ограничен 2 ТБ.
% Это связано с тем, что MBR хранит адреса и размеры блоков в таблице разделов с использованием 32-битных данных.
% Размер одного сектора составляет 512 байт.
% Следовательно, теоретический максимальный размер, который он может хранить, составляет (2^32-1) x 512 байт = 2 ТиБ (2,19 ТБ).
% С другой стороны, таблица разделов GPT может использовать 64-битные.
% Таким образом, теоретический максимальный размер диска с разделами GPT составляет (2^64-1) x 512 байт = 8 ZiB (9,44 ZB).
% Следует отметить, что файловые системы Windows в настоящее время ограничены 256 ТБ каждая.
% 4. Количество разделов
% Как обсуждалось ранее, MBR выделяет 16 байт данных для каждой записи раздела и может выделить всего 64 байта. Таким образом, MBR может адресовать не более 4 основных разделов или 3 основных раздела и 1 расширенный раздел.
% Вы можете иметь неограниченное количество логических разделов в расширенном разделе.
% Однако вы можете установить ОС только в основной раздел. Раздел GPT, с другой стороны, теоретически может иметь неограниченное количество первичных разделов.
% Однако его реализация в Windows ограничена только 128 разделами. Каждый из этих 128 разделов может быть основным разделом.
% Таким образом, вы можете иметь 128 копий ОС, установленных на диске с форматированием GPT.
% 5. Скорость загрузки
% Хотя ни разделы MBR, ни разделы GPT не предназначены для работы быстрее друг друга, между ними может быть некоторая разница в скорости загрузки.
% Это связано с тем, что MBR использует устаревший BIOS, а GPT использует UEFI. Устаревший BIOS проходит процесс Power On Self Test (POST), который проверяет, готово ли всё оборудование к нормальной работе. После этого он ищет MBR для запуска загрузчика, который вызывает ядро ОС, которое затем запускает Windows.
% Напротив, UEFI вызывает загрузчик EFI при запуске, который вызывает ядро, которое затем запускает Windows. Быстрый запуск можно включить в режиме UEFI, который обходит POST для некритичных аппаратных компонентов.
% 6. Безопасность данных
% MBR — это простая схема таблицы разделов, которая объединяет загрузочные данные и разделы. Таким образом, разделы MBR имеют более высокую вероятность потери данных в случае повреждения раздела.
% GPT разделяет таблицу разделов и блоки данных, что обеспечивает более надежную конфигурацию. Кроме того, схема GPT предоставляет дополнительный GPT, который можно использовать в качестве резервной копии в случае повреждения основного GPT. А также, GPT имеет функцию безопасной загрузки, которая предотвращает захват вашего процесса загрузки вредоносными программами. Он также включает проверку циклическим избыточным кодом (CRC) для проверки на предмет повреждения данных.
% Хотя GPT был введен для устранения ограничений MBR и в конечном итоге заменил его, они имеют некоторые общие функции:
% Загрузчик хоста может вызвать ядро ОС, чтобы начать процесс запуска ОС;
% Таблица разделов хоста, в которой хранится информация о размере и расположении разделов;
% Теоретически может быть неограниченное количество разделов. В MBR это происходит из-за возможности назначить четвертый раздел в качестве расширенного раздела, который может содержать неограниченное количество логических разделов. GPT по своей конструкции может содержать неограниченное количество разделов (хотя в Windows это ограничение составляет 124);
% Оба используют логическую адресацию блоков для указания блоков данных;
% MBR хранит основной загрузочный код, а GPT хранит защитную MBR в секторе 1 диска.
% Итак, теперь мы знаем, что такое MBR и GPT. Настало время взглянуть на особенности организации файловой системы в ОС Linux, затем в Windows. Начнём.
% ОС Линукс предоставляет возможность устанавливать в каждый отдельный блок свою файловую систему, которая и будет обеспечивать порядок поступающих и хранящихся данных, поможет с их организацией. Каждая ФС работает на наборе правил. Исходя из этого и определяется в каком месте и каким образом будет выполняться хранение информации. Эти правила лежат в основе иерархии системы, то есть всего корневого каталога. Выше предусмотрен технический блок, отвечающий за организацию хранения данных на определенном типе носителя. Но он уже будет подчиняться правилам файловой системы.
% От того, насколько правильно человек выберет тип файловой системы для каждого раздела зависит ряд параметров:
% скорость обработки данных;
% сбережение файлов;
% оперативность записи;
% допустимый размер блока;
% возможность хранения информации в оперативной памяти;
% способы корректировки пользователями ядра и пр.
% Обмен информацией может осуществляться двумя способами:
% Через VFS виртуальную файловую систему. Здесь обеспечивается слаженное взаимодействие ядра ОС и аппаратного обеспечения, которое используется системой. Останавливая выбор на виртуальной ФС, пользователь сможет работать, не вникая в нюансы любого из видов файловой системы.
% Через драйверы ФС. Это узлы, обеспечивающие стабильную взаимосвязь между аппаратным и программным обеспечением ОС.
% Подводя промежуточный итог, выделим, что файловая система всякой ОС, включая Linux это некая архитектура хранения информации, размещенной на жестком диске и на оперативной памяти. С ее помощью пользователь получает доступ к структуре ядра системы. Он же отвечает за размещение файлов во всех разделах, поддерживая актуальную для него структуру, формирует правила для ее генерации, управляет блоками, исходя из особенностей определенного типа файловой системы.
% Но все же файловая система Linux имеет и свои отличительные особенности. Так, здесь все пространство раздела разбито на узлы разного размера, исходя из кратности сектора: 1024, 2048, 4096, 8120 байт. Эти параметры известны пользователю уже изначально, то есть на момент установки операционной системы. Ограничения здесь идут по размеру файловой системы и требований, установленных в каждой директории.
% Все файловые системы Linux, которые применяются сегодня можно разделить на 2 отдельные категории:
% Журналируемые. Сохраняет историю манипуляций пользователя и позволяет ее посмотреть, выполнить диагностику системы в отдельном специальном файле. Отличается повышенной стойкостью к сбоям в функционировании, сохранностью целостности данных.
% Не журналируемые. Здесь не предусмотрено сбережение логов, нет гарантий сохранности информации. Но зато в работе такие ФМ более быстрые.
% При установке на ПК данной операционной системы, пользователь сможет остановить выбор на следующих разновидностях Linux:
% Ext (extended) FS. Это расширенная файловая система, одна из первых. Была запущена в работу еще в 1992 году. В основе ее функциональности лежала ФС UNIX. Основная задача состояла в выходе за рамки конфигурации классической файловой системы MINIX, исключить ее ограничения и повысить эффективность администрирования. Сегодня она применяется крайне редко.
% Ext2. Вторая, более расширенная вервия ФС, паявшаяся на рынке в 1993 году. По своей структуре продукт аналогичный Ext. Изменения коснулись интерфейса, конфигурации. Увеличился объем памяти, производительность. Максимально допустимый объем файлов для хранения (указывается в настройках) 2 ТБ. Ввиду невысокой перспективности применяется на практике редко.
% Ext3. Третье поколение Extended FS, введенное в использование в 2001 году. Уже относится к журналируемой. Позволяет хранить логи изменения, обновления файлов данных записываются в отдельный журнал еще до того, как эти действия будут завершены. После перезагрузки ПК, такая ФС позволит восстановить файлы благодаря внедрению в систему специального алгоритма.
% Ext4. Четвертое поколение Extended FS, запущенное в 2006 году. Здесь максимально убраны всевозможные ограничения, присутствующие в предыдущих версиях. Сегодня именно она по умолчанию входит в состав большей части дистрибутивов Линукс. Передовой ее нельзя назвать, но стабильность и надежность работы здесь в приоритете. В Unix системах применяется повсеместно.
% Все эти типы имеют различные наборы команд, что и определяет их узкопрофильный функционал. Узнать вид NFS, использующейся на вашем компьютере можно через команду file -s.
% Наряду с основными, предусмотрены и альтернативные типы File System:
% JFS. Журналируемая система, первый аналог продуктам из основной группы, разработанная специалистами IBM под AIX UNIX. Отличается постоянством и незначительными требованиями к работе. Может использоваться на многопроцессорных ПК. Но в ее журнале сохраняются ссылки лишь на метаданные. Поэтому если произойдет сбой, автоматически подтянутся устаревшие версии данных.
% ReiserFS. Создана Гансом Райзером исключительно под Линукс и названа в его честь. По своей структуре это продукт, похожий на Ext3, но с более расширенными возможностями. Пользователи могут соединять небольшие файлы в более масштабные блоки, исключая фрагментацию, повышая эффективность функционирования. Но в случае непредвиденного отключения электроэнергии есть вероятность потерять данные, которые будут группироваться в этот момент.
% XFS. Еще один представитель группы журналируемых файловых систем. Отличительная особенность: в логи программа будет записывать только изменения в метаданных. Из преимуществ выделяют быстроту работы с объемной информацией, способность выделять место для хранения в отложенном режиме. Позволяет увеличивать размеры разделов, а вот уменьшать, удалять часть нельзя. Здесь также есть риск потери данных при отключении электроэнергии.
% Btrfs. Отличается повышенной стойкостью к отказам и высокой производительностью. Удобная в работе, позволяет легко восстанавливать информацию, делать скриншоты. Размеры разделов можно менять в рабочем процессе. По умолчанию входит в OpenSUSE и SUSE Linux. Но обратная совместимость в ней нарушена, что усложняет поддержку.
% F2FS. Разработка Самсунг. Уже входит в ядро Линукс. Предназначена для взаимодействия с хранилищем данных флеш-памяти. Имеет особую структуру: носитель разбивается на отдельные части, которые в свою очередь дополнительно еще делятся.
% OpenZFS. Это ответ на вопрос какую файловую систему выбрать для Ubuntu она автоматически включена в поддержку ОС уже более 6 лет назад. Отличается высоким уровнем защиты от повреждения информации, автоматическим восстановлением, поддержкой больших объемов данных.
% В ядре требуются далеко не все ФС, также и виртуальные, - есть варианты, которые можно осуществить непосредственно в пользовательской среде. Сюда относят сетевые файловые системы и системы для шифрования:
% EncFS. Шифрует данные и пересохраняет их в этом формате в указанную пользователем директорию. Надо примонтировать ФС чтобы обеспечить доступ в расшифрованной информации.
% Aufs. С ее помощью отдельные File Systems можно группировать в один раздел.
% NFS. Позволит через сеть примонтировать ФС удаленного устройства.
% Также, есть и специальные файловые системы:
% Tmpfs. Предусмотрена возможность размещения пользовательских файлов непосредственно в оперативной памяти ПК. Предполагает создание блочного узла определенного размера с последующим подключением к папке. При необходимости данные можно будет удалять.
% Procfs. По умолчанию размещена в папке proc. Буде содержать полный набор данных относительно процессов, запущенных в системе и непосредственно в ядре в режиме реального времени.
% Sysfs. Такая ФС позволит пользователю задавать и отменять параметры ядра во время выполнения задачи.
% Сколько же много всяких возможных файловых систем, теперь бы рассмотреть какие типы файлов вообще существуют в Linux:
% Regular File, они же обычные. Предназначены для хранения двоичной и символьной информации. Это жесткая ссылка, ведущая на фактическую информацию, размещенную в каталоге. Если этой ссылке присвоить уникальное имя, получаем Named Pipe, то есть именованный канал.
% Device File файлы для устройств, туннелей. Речь идет о физических устройствах, представленными в Линукс файлами. Могут классифицировать специальные символы и блоки. Обеспечивают мгновенный доступ к дисководам, принтерам, модемам, воспринимая их как файл данных.
% Soft Link, а именно мягкая (символьная) ссылка. Отвечает за мгновенный доступ к файлам, размещенным на любых носителях информации. В процессе копирования, перемещения и прочего действия пользователя. Предполагающего указание ссылки, будет выполняться операция над документом, на который ссылаются.
% Каталоги. Обеспечивают быстрый и удобный доступ к каталогам. Представляет собой файл с директориями и указателями на них. Это некого рода картотека: в папках размещаются файлы, а в директориях дополнительные каталоги.
% Блочные и символьные устройства. Выделяют интерфейс, необходимый для взаимодействия приложений с аппаратной составляющей.
% Каналы и сокеты. Отвечают за взаимодействие внутренних процессов в операционной системе.
% Windows
% Далее приступим к рассмотрению всей линейке файловых систем для Windows, чтобы понять, какую роль они играют в работе системы и как они развивались в процессе становления Windows плоть до Windows 8.
% Преимущества NTFS касаются практически всего: производительности, надежности и эффективности работы с данными (файлами) на диске. Так, одной из основных целей создания NTFS было обеспечение скоростного выполнения операций над файлами (копирование, чтение, удаление, запись), а также предоставление дополнительных возможностей: сжатие данных, восстановление поврежденных файлов системы на больших дисках и т.д.
% Другой основной целью создания NTFS была реализация повышенных требований безопасности, так как файловые системы FAT, FAT32 в этом отношении вообще никуда не годились. Именно в NTFS можно разрешить или запретить доступ к какому-либо файлу или папке (разграничить права доступа).
% Сначала рассмотрим сравнительные характеристики файловых систем, а потом остановимся на каждой из них поподробнее. Сравнение, для большей наглядности, приведены в табличной форме.
% Файловая система FAT для современных жестких дисков просто не подходит (ввиду ее ограниченных возможностей). Что касается FAT32, то ее еще можно использовать, но уже с натяжкой.
% Если купить жесткий диск на 1000 ГБ, то вам придется разбивать его как минимум на несколько разделов. А если вы собираетесь заниматься видеомонтажом, то вам будет очень мешать ограничение в 4 Гб как максимально возможный размер файла.
% Всех перечисленных недостатков лишена файловая система NTFS. Так что, даже не вдаваясь в детали и специальные возможности файловой системы NTFS, можно сделать выбор в ее пользу.
% .tg {border-collapse:collapse;border-spacing:0;}
% .tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
% overflow:hidden;padding:10px 5px;word-break:normal;}
% .tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
% font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
% .tg .tg-0pky{border-color:inherit;text-align:center;vertical-align:center}
% Файловая система
% Параметры
% Размеры тома
% Максимальный размер файла
% FAT
% От 1.44 МБ до 4 ГБ
% 2ГБ
% FAT32
% Теоретически возможен размер тома от 512 МБ до 2 Тбайт. Сжатие не поддерживается на уровне файловой системы
% 4ГБ
% NTFS
% Минимальный рекомендуемый размер составляет 1,44 МБ, а максимальный - 2 Тбайт. Поддержка сжатия на уровне файловой системы для файлов, каталогов и томов.
% Максимальный размер ограничен лишь размером тома (Теоретически - 264 байт минус 1 килобайт. Практически - 244 байт минус 64 килобайта)
% Вообще использование FAT32 может быть оправдано лишь в тех случаях, когда у вас на компьютере установлено несколько операционных систем, а какая-либо из них не поддерживает NTFS. Но на сегодняшний день таких практически нет. Разве что вы захотите установить у себя антиквариат типа Windows 98.
% Файловая система FAT
% Файловая система FAT (обычно под ней понимается FAT 16) была разработана достаточно давно и предназначалась для работы с небольшими дисковыми и файловыми объемами, простой структурой каталогов. Аббревиатура FAT расшифровывается как File Allocation Table (с англ. таблица размещения файлов). Эта таблица размещается в начале тома, причем хранятся две ее копии (в целях обеспечения большей устойчивости).
% Данная таблица используется операционной системой для поиска файла и определения его физического расположения на жестком диске. В случае повреждения таблицы (и ее копии) чтение файлов операционной системой становится невозможно. Она просто не может определить, где какой файл, где он начинается и где заканчивается. В таких случаях говорят, что файловая система «упала».
% Файловая система FAT изначально разрабатывалась компанией Microsoft для дискет. Только потом они стали ее применять для жестких дисков. Сначала это была FAT12 (для дискет и жестких дисков до 16 МБ), а потом она переросла в FAT16, которая была введена в эксплуатацию с операционной системой MS-DOS 3.0.
% Далее она поддерживается в Windows 3.x, Windows 95, Windows 98, Windows NT/2000 и т.д.
% Файловая система FAT32
% Начиная с Windows 95 OSR2, компания Microsoft начинает активно использовать в своих операционных системах FAT32 - тридцатидвухразрядную версию FAT. Что поделать, технический прогресс не стоит на месте и возможностей FAT 16 стало явно недостаточно.
% По сравнению с ней FAT32 стала обеспечивать более оптимальный доступ к дискам, более высокую скорость выполнения операций ввода/вывода, а также поддержку больших файловых объемов (объем диска до 2 Тбайт).
% В FAT32 реализовано более эффективное расходование дискового пространства (путем использования более мелких кластеров). Выгода по сравнению с FAT16 составляет порядка 10.15%. То есть при использовании FAT32 на один и тот же диск может быть записано информации на 10. 15% больше, чем при использовании FAT16.
% Кроме того, необходимо отметить, что FAT32 обеспечивает более высокую надежность работы и более высокую скорость запуска программ.
% Обусловлено это двумя существенными нововведениями:
% Возможностью перемещения корневого каталога и резервной копии FAT (если основная копия получила повреждения);
% Возможностью хранения резервной копии системных данных.
% Файловая система NTFS
% Ни одна из версий FAT не обеспечивает хоть сколько-нибудь приемлемого уровня безопасности. Это, а также необходимость в добавочных файловых механизмах (сжатия, шифрования) привело к необходимости создания принципиально новой файловой системы. И ею стала файловая система NT (NTFS)
% NTFS — от англ. New Technology File System, файловая система новой технологии. Как уже упоминалось, основным ее достоинством является защищенность: для файлов и папок NTFS могут быть назначены права доступа (на чтение, на запись и т.д.). Благодаря этому существенно повысилась безопасность данных и устойчивость работы системы.
% Назначение прав доступа позволяет запретить/разрешить каким-либо пользователям и программам проделывать какие-либо операции над файлами. Например, не обладая достаточными правами, посторонний пользователь не сможет изменить какой-либо файл. Или не обладая достаточными правами, вирус не сможет испортить файл.
% Кроме того, NTFS, как было сказано выше, обеспечивает лучшую производительность и возможность работы с большими объемами данных.
% Начиная с Windows 2000, используется версия NTFS 5.0, которая, помимо стандартных, позволяет реализовывать следующие возможности:
% Шифрование данных - эта возможность реализуется специальной надстройкой NTFS, которая называется Encrypting File System(EFS) - шифрующая файловая система. Благодаря этому механизму шифрованные данные могут быть прочитаны только на компьютере, на котором произошла шифровка.
% Дисковые квоты - стало возможно назначать пользователям определенный (ограниченный) размер на диске, который они могут использовать.
% Хранение разреженных файлов. Встречаются файлы, в которых содержится большое количество последовательных пустых байтов. Файловая система NTFS позволяет оптимизировать их хранение.
% Использование журнала изменений - позволяет регистрировать все операции доступа к файлам и томам.
% И еще одно нововведение NTFS - точки монтирования. С помощью точек монтирования можно определить различные не связанные между собой папки и даже диски в системе, как один диск или папка. Это имеет большую важность для сбора в одном месте разнородной информации, находящейся в системе.
% Напоследок необходимо иметь в виду, что если для файла под NTFS были установлены определенные права доступа, а потом вы его скопировали на раздел FAT, то все его права доступа и другие уникальные атрибуты, присущие NTFS, будут утеряны. Так что будьте бдительны.
% Устройство NTFS. Главная таблица файлов MFT

Binary file not shown.

View File

@ -6,7 +6,7 @@
\section{Семинар: обработка исключений}
\subsection{Инструментарий}
\begin{itemize}
\item \href{https://docs.google.com}{Презентация} для преподавателя, ведущего семинар;
\item \href{https://docs.google.com/presentation/d/151h8ULUF9r2UyV7QGO4oNiGA4msrywznKeeNMttFdGg}{Презентация} для преподавателя, ведущего семинар;
\item \href{https://drive.google.com/file/d/1LWyE8aEy4-1gsognqhXIXwDcoLviVge4/view}{Фон} GeekBrains для проведения семинара в Zoom;
\item JDK любая 11 версии и выше;
\item \href{https://www.jetbrains.com/idea/download}{IntelliJ IDEA Community Edition} для практики и примеров используется IDEA.
@ -30,21 +30,21 @@
\endhead
@ Организационный момент & 5 tag(beg) & @ 1-5 & @ Преподаватель ожидает студентов, поддерживает активность и коммуникацию в чате, озвучиает цели и планы на семинар. Важно упомянуть, что выполнение домашних заданий с лекции является, фактически, подготовкой к семинару \\
\hline
@ Quiz & 10 & @ 6-18 & @ Преподаватель задаёт вопросы викторины, через 30 секунд демонстрирует слайд-подсказку и ожидает ответов (6 вопросов, по минуте на ответ) \\
@ Quiz & 5 & @ 6-18 & @ Преподаватель задаёт вопросы викторины, через 30 секунд демонстрирует слайд-подсказку и ожидает ответов (6 вопросов, по минуте на ответ) \\
\hline
@ Рассмотрение ДЗ лекции & 10 & @ 19-23 & @ Преподаватель демонстрирует свой вариант решения домашнего задания с лекции, возможно, по предварительному опросу, демонстрирует и разбирает вариант решения одного из студентов \\
\hline
@ Вопросы и ответы & 10 & @ 24 & @ Преподаватель ожидает вопросов по теме прошедшей лекции, викторины и продемонстрированной работы \\
\hline
@ Задание 1 & 30 & @ 25-28 & @ Сквозное задание, состоящее из объяснений в 6 пунктах, обязательных к исполнению. Всё задание выдаётся сразу целиком и является неделимым. \\
@ Задание 1 & 30 & @ 25-35 & @ Сквозное задание, состоящее из объяснений в 6 пунктах, обязательных к исполнению. Всё задание выдаётся сразу целиком и является неделимым. \\
\hline
@ Перерыв (если нужен) & 5 & @ 33 & @ Преподаватель предлагает студентам перерыв на 5 минут (студенты голосуют) \\
@ Перерыв (если нужен) & 5 & @ 36 & @ Преподаватель предлагает студентам перерыв на 5 минут (студенты голосуют) \\
\hline
@ Задание 2 & 30 & @ 29-32 & @ Сквозное задание, состоящее из объяснений в 6 пунктах, обязательных к исполнению. Всё задание выдаётся сразу целиком и является неделимым. \\
@ Задание 2 & 40 & @ 37-49 & @ Сквозное задание, состоящее из объяснений в 6 пунктах, обязательных к исполнению. Всё задание выдаётся сразу целиком и является неделимым. \\
\hline
@ Домашнее задание & 5 & @ 45-46 & @ Объясните домашнее задание, подведите итоги урока \\
@ Домашнее задание & 5 & @ 50-51 & @ Объясните домашнее задание, подведите итоги урока \\
\hline
@ Рефлексия & 10 tag(end) & @ 47-48 & @ Преподаватель запрашивает обратную связь \\
@ Рефлексия & 10 tag(end) & @ 52-53 & @ Преподаватель запрашивает обратную связь \\
\hline
@ Длительность & sum(cell(beg):cell(end)) & & \\
\hline
@ -74,17 +74,29 @@
\end{itemize}
\item \textbf{Вопросы и ответы:}
\begin{enumerate}
\item
\item Перечисление -- это: 2
\begin{enumerate}
\item
\item
\item
\item массив
\item класс
\item объект
\end{enumerate}
\item
\item Инкапсуляция с использованием внутренних классов: 2
\begin{enumerate}
\item
\item
\item
\item остаётся неизменной
\item увеличивается
\item уменьшается
\end{enumerate}
\item Обработчик исключений -- это объект, работающий 1
\begin{enumerate}
\item в специальном потоке
\item в специальном ресурсе
\item в специальный момент
\end{enumerate}
\item Стектрейс - это 2
\begin{enumerate}
\item часть потока выполнения программы;
\item часть объекта исключения;
\item часть информации в окне отладчика.
\end{enumerate}
\end{enumerate}
\end{itemize}
@ -104,7 +116,7 @@
\textbf{Вариант решения}
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Конструктор с вариативностью}]
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Простые наследники}]
private static final class ColumnMismatchException extends RuntimeException {
ColumnMismatchException(String message) {
super("Columns exception: " + message);
@ -120,7 +132,7 @@ private static final class NumberIsNotNumberException extends RuntimeException {
\item Разработайте исключения-наследники так, чтобы они информировали пользователя в формате ожидание/реальность.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Конструктор с вариативностью}]
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Составное сообщение}]
private static final class RowMismatchException extends RuntimeException {
RowMismatchException(int expected, int current, String value) {
super(String.format("Rows exception: expected %d rows. Received %d rows in '%s' string",
@ -247,7 +259,7 @@ public static boolean checkCredentials(String login, String password, String con
\subsubsection{Задание 2}
\begin{itemize}
\item \textbf{Ценность этапа} Написание наброска пет-проекта, повторение информации об ООП, работа с исключениями.
\item \textbf{Тайминг} 25-30 минут.
\item \textbf{Тайминг} 35-40 минут.
\item \textbf{Действия преподавателя}
\begin{itemize}
\item Выдать задание студентам;
@ -335,7 +347,7 @@ while (capacity != orders.length - 1 || i != info.length) {
++i;
}
\end{lstlisting}
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Написание и отладка основного метода}]
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Написание и \textbf{отладка} основного метода}]
private static boolean isInArray(Object[] arr, Object o) {
for (int i = 0; i < arr.length; i++)
if (arr[i].equals(o)) return true;
@ -367,7 +379,7 @@ public static Order buy(Customer who, Item what, int howMuch) {
\end{itemize}
\item \textbf{Задания}
\begin{enumerate}
\item [5-25 мин] Решить все задания (в том числе «со звёздочкой»), если они не были решены на семинаре, без ограничений по времени;
\item [5-25 мин] Выполнить все задания семинара, если они не были решены, без ограничений по времени;
\textbf{Все варианты решения приведены в тексте семинара выше}
\item [15 мин] 1. В класс покупателя добавить перечисление с гендерами, добавить в сотрудника свойство «пол» со значением созданного перечисления. Добавить геттеры, сеттеры.

View File

@ -38,7 +38,7 @@
\newcommand\hrf[1]{\hyperref[#1]{\ref{#1}}}
\newcommand\hRf[1]{\hyperref[#1]{\nameref{#1}}}
\newcommand{\wordcount}{\input{/tmp/wordcount.tex}}
\newcommand{\code}[1]{\small{\texttt{\detokenize{#1}}}\normalsize}
\newcommand{\code}[1]{{\texttt{\detokenize{#1}}}}
\newcommand*{\nom}[2]{#1\nomenclature{#1}{#2}}
\renewcommand\labelitemi{\textemdash}
\newenvironment{frm}