К. Арнольд, Д. Гослинг - Язык программирования Java (1160779), страница 42
Текст из файла (страница 42)
11.1.Рис. 11.1. Иерархия типов в java.io11.2. Класс InputStreamВ абстрактном классе InputStream объявляются методы для чтения из заданного источника. InputStream является базовым классом длябольшинства входных потоков в java.io и содержит следующие методы:public InputStream()Класс InputStream содержит только безаргументный конструктор.public abstract int read() throws IOExceptionЧитает из потока один байт данных и возвращает прочитанное значение, лежащее в диапазоне от 0 до 255 (не от –128 до 127). При достиженииконца потока возвращается флаг –1. Метод блокирует работу программы до появления значения на входе.public int read(byte[] buf) throws IOExceptionЧитает данные в массив байтов.
Метод блокирует работу программы до появления вводимого значения, после чего заполняет buf всемипрочитанными байтами, в количестве не более buf.length. Метод возвращает фактическое количество прочитанных байтов или –1 придостижении конца потока.public int read(byte[] buf, int off, int len) throws IOExceptionЧитает данные в байтовый подмассив.
Метод блокирует работу программы до начала ввода, после чего заполняет часть массива buf, начиная сосмещения off, в количестве до len байтов, если не встретится конец массива buf.public long skip(long count) throws IOExceptionПропускает до count байтов во входном потоке. Количество пропущенных байтов может быть меньше count из-за достижения конца потока.Возвращает фактическое количество пропущенных байтов.public int available() throws IOExceptionВозвращает количество байтов, которые могут быть прочитаны без блокировки работы программы.public void close() throws IOExceptionЗакрывает входной поток.
Метод должен вызываться для освобождения любых ресурсов (например, файловых дескрипторов), связанных спотоком. Если не сделать это, то ресурсы будут считаться занятыми, пока сборщик мусора не вызовет метод finalize данного потока.Приведенная ниже программа подсчитывает общее количество символов и разделителей (white-space characters) в файле:import java.io.*;class CountSpace {public static void main(String[] args)throws IOException{InputStream in;if (args.length == 0)in = System.in;elsein = new FileInputStream(args[0]);int ch;int total;int spaces = 0;for (total = 0; (ch = in.read()) != -1; total++) {if (Character.isSpace((char)ch)spaces++;}}}System.out.println(total + " chars, "+ spaces + " spaces");Программа либо берет имя файла из командной строки, либо читает данные из стандартного входного потока, System.in.
Входной потокпредставлен переменной in. Если имя файла не задано, используется стандартный входной поток; если же оно указано, то создается объектFileInputStream, являющийся расширением InputStream.Цикл for подсчитывает как общее количество символов в файле, так и количество символов-разделителей; для идентификации последнихприменяется метод isSpace класса Character.
В конце происходит вывод результатов. Вот как они выглядят, если программа используется сфайлом, содержащим ее собственный исходный текст:434 chars, 109 spacesВозможно, вам захочется присвоить значение total с помощью метода available, однако для потока System.in такой вариант не сработает. Методavailable возвращает количество байтов, которые могут быть прочитаны без блокировки. Для файла оно обычно представляет собой его длину.Если же поток System.in будет связан с клавиатурой, то возвращаемое методом значение может быть равно нулю; если необработанные символыввода отсутствуют, то следующий вызов read приведет к блокировке.11.3.
Класс OutputStreamАбстрактный класс OutputStream во многих отношениях напоминает InputStream; он абстрагирует поток байтов, направляемых в приемник.Класс содержит следующие методы:public OutputStream()Класс OutputStream содержит только безаргументный конструктор.public abstract void write(int b) throws IOExceptionЗаписывает в поток байт b. Байт передается в виде значения int, поскольку он часто является результатом арифметической операции надбайтами. Выражения, в которых входят данные типа byte, имеют тип int, так что параметр типа int позволяет использовать результат безпреобразования в byte.
Тем не менее обратите внимание на то, что передаются только младшие 8 бит значения int — старшие 24 бита при этомтеряются. Метод блокирует работу программы до завершения записи байта.public void write(byte[] buf) throws IOExceptionЗаписывает в поток содержимое массива байтов. Метод блокирует работу программы до завершения записи.public void write(byte[] buf, int offset, int len) •• throws IOExceptionЗаписывает в поток часть массива байтов, которая начинается с buf [offset] и насчитывает до count байтов, если ранее не будет встречен конецмассива.public void flush() throws IOExceptionОчищает поток, то есть направляет в него все байты, находящиеся в буфере.public void close() throws IOExceptionЗакрывает поток. Метод должен вызываться для освобождения любых ресурсов, связанных с потоком.Если явно не указывается противное, то при обнаружении ошибки в выходном потоке все эти методы возбуждают исключение IOException.Ниже приводится приложение, копирующее свой входной поток в выходной и попутно заменяющее некоторые символы.
Приложение Translateполучает два параметра: строку from и строку to. Если во входном потоке встречается символ, входящий в строку from, он заменяется символомстроки to, находящимся в той же позиции:import java.io.*;class Translate {public static void main(String[] args) {InputStream in = System.in;OutputStream out = System.out;if (args.length != 2)error ("must provide from/to arguments");String from = args[0], to = args[1];int ch, i;if (from.length() != to.length())error ("from and to must be same length");try {}while ((ch = in.read()) != 1) {if ((i = from.indexOf(ch)) != -1)out.write(to.charAt(i));elseout.write(ch);}} catch (IOException e) {error ("I/O Exception: " + e);}public static void error(String err) {System.err.print("Translate: " + err);System.exit(1); // ненулевое значение означает// неблагополучное завершение}}Упражнение 11.1Перепишите приведенную выше программу Translate в виде метода, который пересылает символы из InputStream в OutputStream, а методтрансляции (правило замены символов) и потоки являются параметрами.
Для каждого типа InputStream и OutputStream, о которых говорилось вэтой главе, напишите новый метод main, в котором бы учитывалась возможность трансляции символов при вводе или выводе. Если потоки вводаи вывода оказываются симметричными, то для них может применяться общий метод main.11.4. Стандартные типы потоковКак видно из рис. 11.1, в пакете java.io определяются несколько типов потоков. Обычно они составляют пары ввода/вывода:●●●●●●Конвейерные потоки Piped спроектированы для парного использования, при котором байты, записываемые в PipedOutputStream, могутчитаться из PipedInputStream.Байтовые потоки ByteArray осуществляют ввод/вывод в массив байтов.Фильтрующие потоки Filtered представляют собой абстрактные классы байтовых потоков, в которых с читаемыми байтами выполняютсянекоторые операции-фильтры.
Объект FilterInputStream получает ввод от другого объекта InputStream, некоторым образомобрабатывает (фильтрует) байты и возвращает результат. Фильтрующие потоки могут объединяться в последовательности, при этомнесколько фильтров превращаются в один сквозной фильтр. Аналогичным образом осуществляется и фильтрация вывода — для этогоприменяются различные классы Filter OutputStream.Буферизованные потоки Buffered расширяют понятие фильтрующих потоков, добавляя буферизацию, чтобы при каждом вызове read иwrite не приходилось обращаться к файловой системе.Потоки данных Data разделяются на две категории.
Интерфейсы Data Input и DataOutput определяют методы для чтения и записи данныхвстроенных типов, причем вывод одного из них воспринимается в качестве ввода другого. Эти интерфейсы реализуются классамиDataInputStream и Data OutputStream.Файловые потоки File расширяют понятие фильтрующих потоков — байтовый поток в них связывается с определенным файлом. В нихвстроены некоторые методы, относящиеся к работе с файлами.В пакет также входит ряд потоков ввода (вывода), для которых отсутствуют парные им потоки вывода (ввода):●●●●●Поток SequenceInputStream преобразует последовательность объектов InputStream в один общий InputStream, благодаря чему несколькообъединенных входных потоков могут рассматриваться в виде единого входного потока.StringBufferInputStream использует объект StringBuffer в качестве входного потока.LineNumberInputStream расширяет FilterInputStream и следит за нумерацией строк входного потока.PushbackInputStream расширяет FilterInputStream, добавляя возможность отката на один байт, что оказывается полезным присканировании и синтаксическом анализе входного потока.PrintStream расширяет OutputStream и включает методы print и println для форматирования данных на выводе.