Java: руководство для начинающих (ЛП) - Шилдт Герберт
Шрифт:
Интервал:
Закладка:
Метод 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)