Добавить в цитаты Настройки чтения

Страница 78 из 133

Метод 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.4Second value is 10.1Fourth value is 33.0Here 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()Закрывает поток ввода данных. При последующей попытке чтения генерируется исключение IOExceptionvoid mark (int numChars)Ставит отметку на текущей позиции в потоке. Отметка доступна до тех пор, пока на будет прочитано количество символов, определяемое параметром numCharsboolean markSupported()Возвращает логическое значение true, если поток поддерживает методы mark () и reset ()int read()Возвращает целочисленное представление очередного символа из потока ввода. Если достигнут конец потока, возвращается значение -1int read(char buffer[])Предпринимает попытку прочитать количество байтов, определяемое выражением buffer, length, в массив buffer и возвращает фактическое количество успешно прочитанных символов. Если достигнут конец потока, возвращается значение -1abstract int read(char buffer[], int offset, int numChars)Предпринимает попытку прочитать количество символов, определяемое параметром numChars, в массив buffer, начиная с элемента buffer [ offset]. Если достигнут конец потока, возвращается значение -1int read(CharBuffer buffer)Предпринимает попытку заполнить буфер, определяемый параметром buffer, символами, прочитанными из входного потока. Если достигнут конец потока, возвращается значение -1. CharBuffer — это класс, представляющий последовательность символов, например строкуboolean ready()Возвращает логическое значение true, если следующий запрос на получение символа может быть выполнен немедленно. В противном случае возвращается логическое значение falsevoid 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()Закрывает поток вывода. При последующей попытке записи в поток генерируется исключение IOExceptionabstract void flush()Выводит текущее содержимое буфера на устройство. В результате выполнения данной операции буфер очищаетсяvoid write(int ch)Записывает в вызывающий поток вывода один символ. Параметр ch относится к типу int, что позволяет вызывать данный метод в выражениях, не приводя результат их вычисления к типу charvoid write(char buffer[])Записывает в вызывающий поток вывода массив символов bufferabstract void write(char buffer[], int offset, int numChars)Записывает в вызывающий поток вывода количество символов, определяемое параметром numChars, из массива buffer, начиная с элемента buffer[ offset ]void write(String str)Записывает в вызывающий поток вывода символьную строку strvoid 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)