Работа с FileWriter и FileReader
Отметим, что работа с классом FileWriter ничем не отличается от работы с классом FileOutputStream. Все можно свести к замене наименования классов.
Однако с подклассом FileReader такое утверждение, к сожалению, не верно. Рассмотрим более подробно правила работы с подклассом FileReader.
Первое что необходимо отметить, что при работе с FileReader необходимо объявить не только объект этого класса, но еще и объект класса Scaner. При этом конструктор Scaner-а должен быть проинициализирован уже созданным объектом FileReader-а. Формат:
FileReader Объект = new FileReader("Путь+имяФайла"); Scanner ОбъектСканера = new Scanner(Объект);
Далее необходимо использовать методы класса Scanner, уже обсужденные выше.
Пример.
Замечание.
Работа с методами nextLine() и hasNextLine() полностью аналогична использованию итераторов в коллекциях
Переделаем последний пример предыдущего пункта на использование объектов подкласса FileWriter суперкласса Writer и подкласса FileReader суперкласса Reader. В отличие от предыдущего примера, выполним запись, а затем чтение из одного и того же файла.
Отличительной особенностью исполнения данного примера является разделение работы с файлами на методы.
Кроме того, в данном примере исключительная ситуация будет пробрасываться через цепочку вызовов методами Java-машине через конструкцию throws Исключение.
Пример.
Результат работы программы:
Буферизованные потоки
Базовые потоки ввода-вывода используют небуферизованный ввод- вывод. Это означает, что каждый запрос на чтение или запись обрабатывается непосредственно базовой операционной системой. А поскольку каждый такой запрос часто инициирует доступ к диску, сетевую активность или какую-либо другую относительно дорогостоящую операцию, то использование таких потоков не слишком эффективно.
Буферизация позволяет избежать необходимости обращения к источнику или приемнику при выполнении каждой отдельной операции чтения или записи.
Буферизованные входные потоки считывают данные из области памяти, называемой буфером, а собственный API (Application Programming Interface) ввода вызывается только тогда, когда буфер пуст. Точно так же буферизованные потоки вывода записывают данные в буфер, а собственный API вывода вызывается только при заполнении буфера или принудительной его очистке.
Рассмотрим подробно алгоритм работы буферизированных потоков ввода. Для ввода (чтения) из потока вызывается его метод read(). Если при выполнении read() буферизированного потока выясняется, что буфер потока пуст, то:
вызывается метод read() основного потока-источника данных;
буфер заполняется максимально возможной порцией данных (это или размер буфера, или объем данных источника);
После заполнения буфера управление передается методу read() буферизированного потока и данные будут извлекаться из буфера, пока его содержимое не будет исчерпано, после чего объект буферизированного потока вновь будет вынужден вызвать метод read() потока-источника и т.д.
Совершенно аналогично можно описать алгоритм работы буферизированных потоков вывода. Запись осуществляется методом write() буферизированного потока в буфер. Когда буфер данных заполняется, вызывается write() основного потока-приемника, который освобождает буфер и т.д. Такой механизм позволяет превратить последовательность запросов на вывод (или запись) небольших порций данных в поток-буфер в единственный вызов метода write() потока- приемника.
Метод flush() в данном случае осуществляет очистку буфера, т.е. вывод (запись) всех данных из буфера в поток-приемник вызовом его метода write().
Существует четыре класса буферизованных потоков, используемых для обертки небуферизованных потоков: BufferedInputStream и BufferedOutputStream для создания буферизованных потоков байтов, BufferedReader и BufferedWriter для создания буферизованных потоков символов.
Достарыңызбен бөлісу: |