Java. Полное руководство. 8-е издание. С. Н. Тригуб Перевод с английского и редакция
Скачать 25.04 Mb.
|
6 1 4 Часть II. Библиотека Java // Использование буферизованного ввода Эта программа использует оператор try-с-ресурсами. Требует JDK 7. import java.io.*; class BufferedlnputStreamDemo { public static void main(String a r g s []) { String s = "This is a © copyright symbol " + "but this is © not.Xn"; byte buf[] = s.getBytes(); ByteArraylnputStream in = new ByteArraylnputStream(buf); int с ; boolean marked = false; // Использование Try-с-ресурсами для управления файлами try ( Bufferedlnputstream f = new BufferedlnputStream(in) ) { while ( (c = f.readO) != -1) { switch(c) { case : if (Imarked) { f.mark(32); marked = true; } else { marked = false; } break; case ';': if (marked) { marked = false; System.out.print("(c)"); } else System.out.print((char) c ) ; break; case ' ': if (marked) { marked = false; f .reset (); System.out.print("&"); } else System.out.print((char) c ) ; break; default: if (imarked) System.out.print((char) c ) ; break; } } } c a t c h (IOException e) { System.out.println("I/O Error: " + e) Обратите внимание на то, что этот пример использует метод mar k ( 32 ), что сохраняет метку для чтения следующих 32 байт (чего достаточно для любых ссылок насущности. Вот как выглядит вывод, создаваемый этой программой is ас Глава 19. Ввод-вывод: пакет java.io 6 1 Класс Класс BufferedOutputStream подобен любому классу OutputStream, за исключением дополнительного метода flush(), используемого для обеспечения записи данных в буферизируемый поток. Поскольку назначение класса Buf f eredOutputStream — увеличивать производительность за счет сокращения количества физических записей данных, вам может понадобиться вызывать метод f lush () , чтобы инициировать немедленную запись всех данных из буфера. В отличие от буферизованного ввода, буферизованный вывод не предоставляет дополнительной функциональности. Буферы вывода в Java нужны для повышения производительности. Вот два доступных конструктора этого класса выходнойПоток) BufferedOutputStream(OutputStream выходнойПоток, int размерБуфера) Первая форма создает буферизованный поток, используя размер буфера поумол чанию. Во второй форме размер буфера передается параметром размерБуфера. Класс Одним из новшеств в буферизации является реализация вталкивания (push- back) . Вталкивание используется с потоками ввода, чтобы обеспечить чтение байта с последующим его возвратом (те. втолкнуть) в поток. Класс PushbacklnputStream реализует эту идею. Он представляет механизм для того, чтобы заглянуть во входной потоки увидеть, что оттуда поступит в следующий раз, не извлекая информации. Класс PushbacklnputStream имеет следующие конструкторы входнойПоток) PushbacklnputStream(InputStream входнойПоток, int колБайтов) Первая форма создает объект потока, позволяющий вернуть один байт во входной поток. Вторая форма создает поток, оснащенный буфером вталкивания длиной колБайтов. Это позволяет вернуть во входной поток множество байтов. Помимо знакомых уже методов класса InputStream, класс Pushback lnputStream предлагает метод unread (). void unread(int б unread(byte буфер буфер int смещение int количБайтов) Первая форма вталкивает в поток младший байт б. После этого он вновь будет следующим байтом, возвращаемым последующим вызовом метода read () . Вторая форма вталкивает байты в буфер Третья же форма вталкивает количБайтов байт, начиная с позиции смещение, в буфер Исключение IOException передается в случае попытки втолкнуть байт, когда буфер переполнен. Рассмотрим пример, демонстрирующий, как синтаксический анализатор языка программирования может использовать класс PushbacklnputStream и метод unread (), чтобы справиться с различием между операциями сравнения (= = ) и присваивания (=). / ' / Демонстрация применения unread () . // Эта программа использует оператор try-с-ресурсами. Требует JDK 7. import java.io.*; class PushbacklnputStreamDemo { public static void main(String a r g s []) { String s = "if (a = = 4) a = 0;\n"; byte buf[] = s .getBytes(); ByteArraylnputStream in = new ByteArraylnputStream(buf); 6 1 Часть II. Библиотека Java int с ; try ( PushbacklnputStream f = new PushbacklnputStream(in) ) { while ( (c = f.readO) != -1) { switch(c) { case '=': if ( (c = f.readO ) == ' = ' ) System.out.print(".eq."); else { System.out.print("<-"); f .unread(c); } break; default: System.out.print((char) c ) ; break; } } } c a t c h (IOException e) { System.out.println("I/O Error: " + e ) Ниже показан вывод этого примера. Обратите внимание на то, что 11 = =" заменяется на " . e q . ", а " =" — на "<- ". if (a .eq. 4) а- Внимание Класс PushbacklnputStream обладает побочным эффектом — он делает невозможным использование методов mark () и reset () потока класса inputstream, использованного для его создания. Применяйте метод markSupported ( ) , чтобы проверить каждый поток на предмет возможности использования методов mark () и reset (Класс S e q u e n c e ln p u t S t r e a Класс SequencelnputStream позволяет соединять вместе несколько экземпляров класса Inputstream. Создание объекта класса SequencelnputStream отличается от создания объекта класса Inputstream. Конструктор класса SequencelnputStream принимает в качестве аргумента либо пару объектов класса Inputstream, либо интерфейс Enumeration из объекта класса Inputstream. SequencelnputStream(Inputstream первый Inputstream второй) SequencelnputStream(Enumeration extends InputStream> перечПотоков) Во время работы класс выполняет запросы на чтение из первого объекта класса Inputstream и до конца, а затем переключается на второй. В случае интерфейса Enumeration работа продолжится по всем объектам классам Inputstream, пока не будет достигнут конец последнего. По достижении конца каждого файла, связанный с ним поток закрывается. Закрытие потока, созданного объектом класса SequencelnputStream, приводит к закрытию всех открытых потоков. Вот простой пример использования класса SequencelnputStream для вывода содержимого двух файлов. В демонстрационных целях эта программа использует традиционную методику закрытия файла. В качестве упражнения вы могли бы попробовать изменить его так, чтобы использовать оператор try - с - ресурсами Демонстрация последовательного ввода Эта программа использует оператор try-с-ресурсами. Требует JDK 7. Глава 19. Ввод-вывод: пакет java.io 6 1 7 import java.io.*; import java.util.*; class InputStreamEnumerator implements Enumeration private Enumeration public InputStreamEnumerator(Vector this.files = files.elements(); } public boolean hasMoreElements() { return files.hasMoreElements(); } public Filelnputstream nextElement() { try { return new Filelnputstream(files.nextElement().toString()); } catch (IOException e) { return null; } } } class SequencelnputStreamDemo { public static void main(String a r g s []) { int с ; Vector files.addElement("filel.txt") files.addElement("file2.txt") files.addElement("file3.txt") , InputStreamEnumerator ise = new InputStreamEnumerator(files); InputStream input = new SequencelnputStream(ise); try { while ((c = input.r e a d ()) != -1) System.out.print((char) c ) ; } catch(NullPointerException e) { System.out.println("Error Opening File."); } c a t c h (IOException e) { System.out.println("I/O Error: " + e) ; } finally { try { input.c l o s e (); } c a t c h (IOException e) { System.out.println("Error Closing Этот пример создает объект класса Vector и затем добавляет к нему три имени файла. Затем этот вектор с именами передается классу InputStreamEnumerator, предназначенному служить оболочкой вектора, в которой элементы возвращаются не в виде имен файлов, а в виде открытых объектов класса Filelnputstream, созданных по этим именам. Объект класса SequencelnputStream открывает каждый файл по очереди, и таким образом этот пример выводит содержимое этих файлов. О братите внимание на то, что если файл в методе nextElement () не может быть открыт, возвращается значение null. В результате передается исключение NullPointerException, обрабатываемое в функции main (). 6 1 Часть II. Библиотека Класс P r i n t S t r e a Класс PrintStream предоставляет все возможности вывода, которыми мы пользуемся с дескриптором System.out файла класса System с самого начала нашей книги. Это делает класс PrintStream одним из наиболее часто используемых классов Java. Он реализует интерфейсы Appendable, AutoCloseable, Closeable и Класс PrintStream определяет несколько конструкторов. Для начала рассмотрим перечисленные ниже выходнойПоток) PrintStream(OutputStream выходнойПоток, boolean сбросПриНовойСтроке) PrintStream(OutputStream выходнойПоток, boolean сбросПриНовойСтроке, S t r i n g наборСимволов) throws Здесь выходнойПоток указывает открытый объект класса OutputStream, который будет принимать вывод. Параметр сбросПриНовойСтроке управляет тем, будет ли выходной буфер автоматически сбрасываться при каждой записи символа новой строки п, записи байтового массива либо вызове метода println (). Если аргумент сбросПриНовойСтроке равен значению true, происходит автоматический сброс. Если же он равен значению f a l s e , сброс будет неавтоматиче ским. Первый конструктор не включает автоматический сброс. Вы можете задать кодировку символов, передав ее имя в параметре наборСимволов. Следующий набор конструкторов предоставляет простые способы создания объекта класса PrintStream, который пишет свой вывод в файл выходнойФайл) throws FileNotFoundException PrintStream(File выходнойФайл, String наборСимволов) throws FileNotFoundException, UnsupportedEncodingException PrintStream(String имяВыходногоФайла) throws FileNotFoundException PrintStream(String имяВыходногоФайла, String наборСимволов) throws FileNotFoundException, UnsupportedEncodingException Они позволяют создавать объект класса PrintStream на основе объекта класса File либо имени файла. В любом случае файл создается автоматически. Любой существующий файл стем же именем уничтожается. Будучи созданным, объект класса PrintStream управляет всем выводом в указанный файл. Кодировку символов можно указать в параметре наборСимволов. Класс PrintStream поддерживает методы print () и println () для всех типов, включая тип Object. Если аргумент не относится к элементарному типу, то методы класса PrintStream вызывают метод toString () объекта, а затем отображают его результат. Не так давно (споявлением версии JDK 5) вкласс Stream был добавлен метод print f () . Он позволяет задать точный формат вывода записываемых данных. Метод print f () использует класс Formatter описанный в главе 18) для форматирования данных. Затем он выводит эти данные в вызывающий поток. Хотя форматирование может выполняться вручную за счет непосредственного использования класса Formatter, все же метод print f () существенно упрощает процесс. Он является аналогом функции C/C++ print f (), облегчая преобразование существующего кода C/C++ в Java. Откровенно говоря, метод print f () — весьма полезное дополнение к Java API, поскольку значительно упрощает вывод форматированных данных на консоль. Метод print f () имеет следующие общие формы p r i n t f (String формСтрока, Object ... аргументы printf(Locale регион формСтрока, Object ... аргументы) Первая версия записывает аргументы в стандартный вывод в формате, указанном формСтрока , используя локальные установки по умолчанию. Вторая версия Глава 19. Ввод-вывод: пакет java.io 6 1 позволяет указать региональные данные. Обе возвращают вызывающий объект класса В общем случае метод printf () подобен методу format ( ), который определен в классе Formatter. Параметр формСтрока состоит из элементов двух типов. Первый тип содержит символы, которые просто копируются в выходной буфер, второй тип — спецификаторы формата, определяющие способ отображения последующих аргументов — аргументы За полной информацией о форматированном выводе, включая описание спецификаторов формата, обращайтесь к описанию класса Formatter в главе Поскольку поток System.out имеет тип PrintStream, вы можете вызывать метод printf () с потоком System, out. Поэтому метод printf () может служить в качестве замены метода println(), когда необходимо выдавать на консоль форматированный вывод. Например, в следующей программе метод printf () используется для вывода числовых значений в различных форматах. До JDK 5 такое форматирование требовало существенной работы. С появлением метода printf () оно значительно упростилось Демонстрация применения pr i n t f О . class PrintfDemo { public static void main(String a r g s []) Ниже следуют некоторые числовые значения " +в различных форматах.\п"); System.out.printf("Различные целочисленные форматы "); System.out.printf("%d %(d %+d %05d\n", 3, -3, 3, Формат с плавающей точкой по умолчанию п, Плавающая точка с запятыми % /f\n"/ 1234567.123); System.out.p r i n t f (Отрицательная плавающая точка по умолчанию %,f\n", -Параметры отрицательной плавающей точки: %,(f\п", -1234567.123); System.out.p r Строка из положительных и отрицательных значений:\п"); System.out.printf("% ,.2f\n% Вывод этой программы. Ниже следуют некоторые числовые значения в различных форматах. Различные целочисленные форматы 3 (3) +3 Формат с плавающей точкой по умолчанию 123 45 67.123 000 Плавающая точка с запятыми Отрицательная плавающая точка по умолчанию -1,234,567.123000 Параметры отрицательной плавающей точки (Строка из положительных и отрицательных значений: 1,234,567.12 -1,234,567.12 В классе PrintStream определен также метод format () . Вот его общие формы 6 2 Часть II. Библиотека Java PrintStream format(String формСтрока, Object ... аргументы format(Locale регион формСтрока, Object ... аргументы) Он работает точно также, как метод print f (Классы DataOutputStream и Эти классы позволяют писать или читать элементарные данные в потоки из него. Они реализуют интерфейсы DataOutput и Datalnput соответственно. Эти интерфейсы определяют методы, преобразующие элементарные значения в форму последовательности байтов. Такие потоки облегчают сохранение в файле двоичных данных, таких как целочисленные значения или значения с плавающей точкой. Рассмотрим здесь и то, и другое. Класс DataOutputStream расширяет класс FilterOutputStream, который, в свою очередь, расширяет класс OutputStream. Кроме реализации интерфейса, класс DataOutputStream реализует также интерфейсы AutoCloseable, Closeable и Flushable. В классе DataOutputStream определен следующий конструктор выходнойПоток) Здесь выходнойПоток определяет выходной поток, в который будут записаны данные. Когда поток класса DataOutputStream закрывается (при вызове метода close () ), основной поток, определенный аргументом выходнойПоток , также закрывается автоматически. Класс DataOutputStream поддерживает все методы, определенные его супер классами. Однако он реализует методы, определенные интерфейсом DataOutput, которые и делают его интересным. Интерфейс определяет методы, преобразующие значения элементарных типов в последовательности байтов, аза тем записывающие их в лежащий в основе поток. Вот образцы этих методов void writeDouble(double значение throws IOException final void writeBoolean(boolean значение throws IOException final void writelnt(int значение throws Здесь значение — это значение, записываемое в поток. Класс Datalnput St ream — это дополнение класса DataOutputStream. Он расширяет класс FilterlnputStream, который, в свою очередь, расширяет класс Inputstream. Кроме реализации интерфейса Datalnput, класс Datalnput Stream реализует также интерфейсы AutoCloseable и Closeable. Он определяет только один следующий конструктор входнойПоток) Здесь входнойПоток определяет входной поток, откуда будут читаться данные. Когда поток класса DatalnputStream закрывается (при вызове метода close ()), основной поток, определенный аргументом входнойПоток , также закрывается автоматически. Как и класс DataOutputStream, класс DatalnputStream поддерживает все методы своих суперклассов, наряду с методами, определенными интерфейсом Datalnput, что и делает его уникальным. Эти методы читают последовательность байтов и преобразуют их в значения элементарных типов. Ниже показаны образцы этих методов double readDouble( ) |