Чтение онлайн

ЖАНРЫ

Java: руководство для начинающих
Шрифт:

Здесь конкретный файл указывается с помощью параметра имя_файла, а параметр доступ определяет, какой именно тип доступа будет использоваться для обращения к файлу. Если параметр доступ принимает значение "г", то данные могут читаться из файла, но не записываться в него. Если же указан тип доступа "rw", то файл открывается как для чтения, так и для записи.

Метод seek , общая форма объявления которого приведена ниже, служит для установки текущего положения указателя файла, void seek(long newPos) throws IOException

Здесь параметр newPos определяет новое положение указателя файла в байтах относительно начала файла. Операция чтения или записи, следующая после вызова метода seek , будет выполняться относительно нового положения указателя файла.

В классе RandomAccessFile определены методы read и write . Этот класс также реализует интерфейсы Datalnput и DataOuput, т.е. в нем доступны методы чтения и записи простых типов, например readlnt и writeDouble .

Ниже приведен пример программы, демонстрирующий ввод-вывод с произвольным доступом.

В этой программе шесть значений типа double сначала записываются в файл, а затем читаются из него, причем порядок чтения их отличается от порядка записи. // Демонстрация произвольного доступа к файлам. // Для компиляции этого кода требуется JDK 7 // или более поздняя версия данного комплекта. import java.io.*; class RandomAccessDemo { public static void main(String args[]) { double data[] = { 19.4, 10.1, 123.54, 33.0, 87.9, 74.25 }; double d; // открыть и использовать файл с произвольным доступом // Файл с произвольным доступом открывается для записи и чтения. try (RandomAccessFile raf = new RandomAccessFile("random.dat", "rw")) { // записать значения в Файл for(int i=0; i < data.length; i++) { raf.writeDouble(data[i]); } //а теперь прочитать отдельные значения из файла // Для установки указателя файла служит метод seek. raf.seek(0); // найти первое значение типа double d = raf.readDouble; System.out.println("First value is " + d) ; raf.seek(8); // найти второе значение типа double d = raf.readDouble; System.out.println("Second value is " + d) ; raf.seek(8 * 3); // найти четвертое значение типа double d = raf.readDouble; System.out.println("Fourth value is " + d); System.out.println; // а теперь прочитать значения через одно System.out.println("Here is every other value: "); for(int i=0; i < data.length; i+=2) { raf.seek(8 * i); // найти i-e значение типа double d = raf.readDouble; System.out.print(d + " ") ; } } catch(IOException exc) { System.out.println("I/O Error: " + exc) ; } } }

Результат выполнения данной программы выглядит следующим образом: First value is 19.4 Second value is 10.1 Fourth value is 33.0 Here is every other value: 19.4 123.54 87.9

Обратите внимание на расположение каждого числового значения. Ведь значение типа double занимает 8 байтов, и поэтому каждое последующее число начинается на 8-байтовой границе предыдущего числа. Иными словами, первое числовое значение начинается на позиции нулевого байта, второе — на позиции 8-го байта, третье — на позиции 16-го байта и т.д. Поэтому для чтения четвертого числового значения нужно установить указатель файла на позиции 24-го байта при вызове метода seek . Применение символьных потоков в Java

Как следует из предыдущих разделов этой главы, байтовые потоки в Java довольно эффективны и удобны в употреблении. Но что касается ввода-вывода символов, то байтовые потоки далеки от идеала. Поэтому для этих целей в Java определены классы символьных потоков. На вершине иерархии классов, поддерживающих символьные потоки, находятся абстрактные классы Reader и Writer. Методы класса Reader приведены в табл. 10.7, а методы класса Writer — в табл. 10.8. В большинстве этих методов может быть сгенерировано исключение IOException. Методы, определенные в указанных абстрактных классах Reader и Writer, доступны во всех их подклассах. Таким образом, они образуют минимальный набор функций ввода-вывода, необходимых для всех символьных потоков.

Таблица 10.7. Методы, определенные в классе Reader Метод Описание abstract void close Закрывает поток ввода данных. При последующей попытке чтения генерируется исключение IOException void mark (int numChars) Ставит отметку на текущей позиции в потоке. Отметка доступна до тех пор, пока на будет прочитано количество символов, определяемое параметром numChars boolean markSupported Возвращает логическое значение true, если поток поддерживает методы mark и reset int read Возвращает целочисленное представление очередного символа из потока ввода. Если достигнут конец потока, возвращается значение -1 int read(char buffer[]) Предпринимает попытку прочитать количество байтов, определяемое выражением buffer, length, в массив buffer и возвращает фактическое количество успешно прочитанных символов. Если достигнут конец потока, возвращается значение -1 abstract int read(char buffer[], int offset, int numChars) Предпринимает попытку прочитать количество символов, определяемое параметром numChars, в массив buffer, начиная с элемента buffer [ offset]. Если достигнут конец потока, возвращается значение -1 int read(CharBuffer buffer) Предпринимает попытку заполнить буфер, определяемый параметром buffer, символами, прочитанными из входного потока. Если достигнут конец потока, возвращается значение -1. CharBuffer — это класс, представляющий последовательность символов, например строку boolean ready Возвращает логическое значение true, если следующий запрос на получение символа может быть выполнен немедленно. В противном случае возвращается логическое значение false void reset Устанавливает указатель ввода на помеченной ранее позиции long skip(long numChars) Пропускает количество символов, определяемое параметром numChars, в потоке ввода. Возвращает фактическое количество пропущенных символов

Таблица 10.8. Методы, определенные в классе Writer Метод Описание Writer append(char ch) Записывает символ ch в конец текущего потока. Возвращает ссылку на поток Writer append(CharSequence chars) Записывает символы chars в конец текущего

потока. Возвращает ссылку на поток. CharSequence — это интерфейс, в котором описаны только операции чтения последовательности символов Writer append(CharSequence chars, int begin, int end) Записывает символы chars в конец текущего потока, начинаяс позиции, определяемой параметром begin, и кончая позицией, определяемой параметром end. Возвращает ссылку на поток. CharSequence — это интерфейс, в котором описаны только операции чтения последовательности символов abstract void close Закрывает поток вывода. При последующей попытке записи в поток генерируется исключение IOException abstract void flush Выводит текущее содержимое буфера на устройство. В результате выполнения данной операции буфер очищается void write(int ch) Записывает в вызывающий поток вывода один символ. Параметр ch относится к типу int, что позволяет вызывать данный метод в выражениях, не приводя результат их вычисления к типу char void write(char buffer[]) Записывает в вызывающий поток вывода массив символов buffer abstract void write(char buffer[], int offset, int numChars) Записывает в вызывающий поток вывода количество символов, определяемое параметром numChars, из массива buffer, начиная с элемента buffer[ offset ] void write(String str) Записывает в вызывающий поток вывода символьную строку str void write(String str, int offset, int numChars) Записывает в вызывающий поток вывода часть numChars символов из строки str, начиная с позиции, обозначаемой параметром offset Консольный ввод из символьных потоков

Если программа подлежит локализации, то при организации ввода с консоли символьным потокам следует отдать предпочтение перед байтовыми. А поскольку System.in — это байтовый поток, то для него придется построить оболочку в виде класса, производного от класса Reader. Наиболее подходящим для ввода с консоли является класс Buf feredReader, поддерживающий буферизованный поток ввода. Но объект типа Buf feredReader нельзя построить непосредственно из потока стандартного ввода System, in. Сначала нужно преобразовать байтовый поток в символьный. И для этой цели служит класс InputStreamReader, преобразующий байты в символы. Для того чтобы получить объект типа InputStreamReader, связанный с потоком стандартного ввода System, in, нужно воспользоваться следующим конструктором: InputStreamReader(InputStream inputStream)

Поток ввода System.in является экземпляром класса InputStream, и поэтому его можно указать в качестве параметра inputStream данного конструктора.

Затем на основании объекта типа InputStreamReader можно создать объект типа BufferedReader, используя следующий конструктор: BufferedReader(Reader inputReader)

где inputReader — это поток, который связывается с создаваемым экземпляром класса Buf feredReader. Объединяя обращения к указанным выше конструкторам в одну операцию, мы получаем приведенную ниже строку кода. В ней создается объект типа BufferedReader, связанный с клавиатурой. BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

После выполнения этого оператора присваивания переменная br будет содержать ссылку на символьный поток, связанный с консолью через поток ввода System.in. Чтение символов

Прочитать символы из потока ввода System, in можно с помощью метода read, определенного в классе Buf f eredReader. Чтение символов мало чем отличается от чтения данных из байтовых потоков. Ниже приведены общие формы объявления трех вариантов метода read , предусмотренных в классе Buf f eredReader. int read throws IOException int read(char data[]) throws IOException int read(char data[], int start, int max) throws IOException

В первом варианте метод read читает один символ в уникоде. По достижении конца потока этот метод возвращает значение -1. Во втором варианте метод read читает данные из потока ввода и помещает их в массив. Чтение оканчивается по достижении конца потока, по заполнении массива data символами или при возникновении ошибки. В этом случае метод возвращает число прочитанных символов, а если достигнут конец потока, — значение -1. В третьем варианте метод read помещает прочитанные символы в массив data, начиная с элемента, определяемого индексом start. Максимальное число символов, которые могут быть записаны в массив, определяется параметром max. В данном случае метод возвращает число прочитанных символов или значение -1, если достигнут конец потока. При возникновении ошибки в каждом из перечисленных выше вариантов метода read генерируется исключение IOException. При чтении данных из потока ввода System, in конец потока устанавливается нажатием клавиши < Enter>.

Ниже приведен пример программы, демонстрирующий применение метода read для чтения символов с консоли. Символы читаются до тех пор, пока пользователь не введет точку. Следует иметь в виду, что исключения, которые могут быть сгенерированы при выполнении данной программы, обрабатываются за пределами метода main . Как пояснялось выше, подобный подход характерен для обработки ошибок при чтении данных с консоли. По желанию вы можете употребить другой механизм обработки ошибок. // Применение класса BufferedReader для чтения символов с консоли, import java.io.*; class ReadChars { public static void main(String args[]) throws IOException { char c; // Создание объекта типа BufferedReader, связанного // с потоком стандартного ввода System.in. BufferedReader br = new BufferedReader(new InputStreamReader'(System. in) ) ; System.out.println("Enter characters, period to quit."); // читать символы do { с = (char) br.read; System.out.println(c) ; } while(c != '.'); } }

Поделиться с друзьями: