Текст книги "Java: руководство для начинающих (ЛП)"
Автор книги: Герберт Шилдт
Жанр:
Программирование
сообщить о нарушении
Текущая страница: 22 (всего у книги 36 страниц)
Выполнение этой программы дает следующий результат: Writing 10 Writing 1023.56 Writing true Writing 90.28 Reading 10 Reading 1023.56 Reading true Reading 90.28
Пример для опробования 10.1. Утилита сравнения файлов
В этом проекте предстоит создать простую, но очень полезную утилиту для сравнения содержимого файлов. В ходе выполнения этой сервисной программы сначала открываются два сравниваемых файла, а затем данные читаются из них и сравниваются по соответствующему количеству байтов. Если на какой-то стадии операция сравнения дает отрицательный результат, это означает, что содержимое обоих файлов не одинаково. Если же конец обоих файлов достигается одновременно, это означает, что они содержат одинаковые данные.
Последовательность действий
Создайте файл CompFiles.java.
Введите в файл CompFiles.java приведенный ниже исходный код. /* Для того чтобы воспользоваться этой программой, укажите имена сравниваемых файлов в командной строке, например: java CompFile FIRST.TXT SECOND.TXT Для компиляции этого кода требуется JDK 7 или более поздняя версия данного комплекта. */ import java.io.*; class CompFiles { public static void main(String args[]) { int i=0, j=0; // Прежде всего следует убедиться, что файлы были указаны, if(args.length !=2 ) { System.out.println("Usage: CompFiles fl f2"); return; } // сравнить файлы try (FilelnputStream fl = new FilelnputStream(args[0]); FilelnputStream f2 = new FilelnputStream(args[1])) { // проверить содержимое каждого файла do { i = f1.read(); j = f2.read(); if(i != j) break; } while (i != -1 && j != -1) ; if(i != j) System.out.println("Files differ."); else System.out.println("Files are the same."); } catch(IOException exc) { System.out.println("I/O Error: " + exc); } } }
Для опробования программы скопируйте сначала файл CompFiles. java во временный файл temp, а затем введите в командной строке следующее:java CompFiles CompFiles.java temp
Программа сообщит, что файлы одинаковы. Далее сравните файл CompFiles.java с рассмотренным ранее файлом CopyFile. j ava, введя в командной строке следующее:java CompFiles CompFiles.java CopyFile.java
Эти файлы содержат разные данные, о чем и сообщит программа CompFiles.
Попробуйте самостоятельно внедрить в программу CompFiles ряд дополнительных возможностей. В частности, введите в нее возможность выполнять сравнение без учета регистра символов. Программу CompFiles можно также доработать таким образом, чтобы она выводила место, где обнаружено первое отличие сравниваемых файлов. Файлы с произвольным доступом
До сих пор нам приходилось иметь дело с последовательными файлами, содержимое которых вводилось и выводилось побайтно, т.е. строго по порядку. Но в Java предоставляется также возможность обращаться к хранящимся в файле данным в произвольном порядке. Для этой цели предусмотрен класс RandomAccessFile, инкапсулирующий файл с произвольным доступом. Класс RandomAccessFile не является производным от класса InputStream или OutputStream. Вместо этого он реализует интерфейсы Datalnput и DataOutput, в которых объявлены основные методы ввода-вывода. В нем поддерживаются также запросы позиционирования, т.е. возможность задавать положение указателя файла произвольным образом. Ниже приведен конструктор класса RandomAccessFile, которым мы будем пользоваться далее. RandomAccessFile(String имя_файла, String доступ) throws FileNotFoundException
Здесь конкретный файл указывается с помощью параметра имя_файла, а параметр доступ определяет, какой именно тип доступа будет использоваться для обращения к файлу. Если параметр доступ принимает значение "г", то данные могут читаться из файла, но не записываться в него. Если же указан тип доступа "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 != '.'); } }
Результат выполнения данной программы выглядит следующим образом: Enter characters, period to quit. One Two. O n e T w о Чтение символьных строк
Для ввода символьной строки с клавиатуры следует воспользоваться методом readLine () из класса Buf feredReader. Ниже приведена общая форма объявления этого метода. String readLine() throws IOException
Этот метод возвращает объект типа String, содержащий прочитанные символы. При попытке прочитать символьную строку по окончании потока метод возвращает пустое знчение null.
Ниже приведен пример программы, демонстрирующий применение класса BufferedReader и метода readLine (). В этой программе текстовые строки читаются и отображаются до тех пор, пока не будет введено слово "stop". // Чтение символьных строк с консоли средствами класса BufferedReader. import java.io.*; class ReadLines { public static void main(String args[]) throws IOException { // создать объект типа BufferedReader, связанный с потоком System.in BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str; System.out.println("Enter lines of text."); System.out.println("Enter 'stop' to quit."); do { // использовать метод readLine() из класса BufferedReader // для чтения текстовой строки str = br.readLine(); System.out.println(str) ; } while(!str.equals("stop")) ; } } Консольный вывод в символьные потоки
Несмотря на то что поток стандартного вывода System, out вполне может использоваться для вывода на консоль, такой подход скорее пригоден для целей отладки или при создании очень простых программ, подобных тем, которые приводятся в качестве примеров в этой книге. Для реальных прикладных программ на Java вывод на консоль обычно организуется через поток PrintWriter, относящийся к одному из классов, представляющих символьные потоки. Как упоминалось ранее, применение символьных потоков упрощает локализацию прикладных программ.
В классе PrintWriter определен ряд конструкторов. Далее будет использоваться следующий конструктор: PrintWriter(OutputStream OutputStream, boolean flushOnNewline)
где в качестве первого параметра OutputStream конструктору передается объект типа OutputStream, а второй параметр f lushOnNewline указывает, должен ли производиться вывод данных из буфера в поток вывода при каждом вызове метода println (). Если параметр f lushOnNewline принимает логическое значение true, данные выводятся из буфера автоматически.
В классе PrintWriter поддерживаются методы print () и println () для всех типов, включая Object. Следовательно, методы print () и println () можно использовать точно так же, как и вместе с потоком вывода System, out. Если значение аргумента не относится к простому типу, то методы из класса PrintWriter вызывают метод toString () для объекта, указываемого в качестве параметра, а затем выводят результат.
Для вывода данных на консоль через поток типа PrintWriter следует указать System.out B качестве потока вывода и обеспечить вывод данных из буфера после каждого вызова метода println (). Например, при выполнении следующей строки кода создается объект типа PrintWriter, связанный с консолью: PrintWriter pw = new PrintWriter(System.out, true);
Ниже приведен пример прикладной программы, демонстрирующий применение класса PrintWriter для организации вывода на консоль. // Применение класса PrintWriter. import java.io.*; public class PrintWriterDemo { public static void main(String args[]) { // Создание объекта типа PrintWriter, связанного // с потоком стандартного вывода System.out. PrintWriter pw = new PrintWriter(System.out, true); int i = 10; double d = 123.65; pw.println("Using a PrintWriter."); pw.println(i); pw.println(d); pw.println(i + " + " + d + " is " + (i+d)); } }
Выполнение этой программы дает следующий результат: Using a PrintWriter. 10 123.65 10 + 123.65 is 133.65
Несмотря на все удобство символьных потоков, не следует забывать, что для изучения языка Java или отладки программ можно вполне пользоваться и потоком вывода System, out. Но если в программе применяется поток PrintWriter, то ее проще локализировать. Для кратких примеров программ, представленных в этой книге, применение потока PrintWriter не имеет существенных преимуществ перед потоком System, out, поэтому в и последующих примерах для вывода на консоль будет использоваться поток System.out. Ввод-вывод в файлы через символьные потоки
На практике чаще всего приходится обращаться с файлами, имеющими байтовую организацию, тем не менее, для этой цели можно пользоваться символьными потоками. Преимущество символьных потоков заключается в том, что они оперируют непосредственно символами в уникоде. Так, если требуется сохранить текст в уникоде, для этой цели лучше всего воспользоваться символьными потоками. Как правило, для файлового ввода-вывода символов служат классы FileReader и FileWriter. Применение класса FileWriter
Класс FileWriter представляет поток, через который можно осуществлять запись данных в файл. Ниже приведены общие формы объявления двух наиболее часто употребляемых конструкторов данного класса. FileWriter(String имя_файла) throws IOException FileWriter(String имя_файла, boolean append) throws IOException
Здесь имя файла обозначает полный путь к файлу. Если параметр append принимает логическое значение true, данные записываются в конец файла, а иначе они перезаписывают прежние данные на том же месте в файле. При возникновении ошибки в каждом из указанных выше конструкторов генерируется исключение IOException. Класс FileWriter является производным от классов OutputStreamWriter и Writer. Следовательно, в нем доступны методы, объявленные в его суперклассах.
Ниже приведен краткий пример программы, демонстрирующий ввод текстовых строк с клавиатуры и последующий их вывод в файл test. txt. Набираемый текст читается до тех пор, пока пользователь не введет слово "stop". Для вывода текстовых строк в файл используется класс FileWriter. // Простой пример утилиты ввода с клавиатуры и вывода данных // на диск, демонстрирующий применение класса FileWriter. // Для компиляции этого кода требуется JDK 7 // или более поздняя версия данного комплекта. import java.io.*; class KtoD { public static void main(String args[]) { String str; BufferedReader br = new BufferedReader( new InputStreamReader(System.in)); System.out.println("Enter text ('stop' to quit)."); // Создание потока вывода типа FileWriter. try (FileWriter fw = new FileWriter("test.txt")) { do { System.out.print(": "); str = br.readLine(); if(str.compareTo("stop") == 0) break; str = str + "rn"; // add newline // Запись текстовых строк в файл, fw.write(str); } while(str.compareTo("stop") != 0) ; } catch(IOException exc) { System.out.println("I/O Error: " + exc); } } } Применение класса FileReader
В классе FileReader создается объект типа Reader, который можно использовать для чтения содержимого файла. Чаще всего употребляется такой конструктор этого класса: FileReader(String имя_файла) throws FileNotFoundException
где имя файла обозначает полный путь к файлу. Если указанный файл не существует, генерируется исключение FileNotFoundException. Класс FileReader является производным от классов InputStreamReader и Reader. Следовательно, в нем доступны методы, объявленные в его суперклассах.
Приведенный ниже пример демонстрирует простую утилиту для отображения на экране содержимого текстового файла test. txt. Она является своего рода дополнением к утилите, рассмотренной в предыдущем разделе. // Простая утилита ввода с дйска и вывода на экран, // демонстрирующая применение класса FileReader. // Для компиляции этого кода требуется JDK 7 // или более поздняя версия данного комплекта. import java.io.*; class DtoS { public static void main(String args[]) { String s; // Создание в классе BufferedReader оболочки с целью заключить // в нее класс FileReader и организовать чтение данных из файла. try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) { while((s = br.readLine()) != null) { System.out.println(s) ; } } catch(IOException exc) { System.out.println("I/O Error: " + exc) ; } } }
Обратите внимание на то, что для потока типа FileReader создана оболочка в классе BufferedReader. Благодаря этому появляется возможность обращаться к методу readLine (). Кроме того, закрытие потока типа Buf feredReader, на который в данном примере ссылается переменная br, автоматически приводит к закрытию файла. Применение оболочек типов для преобразования символьных строк в числа
Прежде чем завершить обсуждение средств ввода-вывода, необходимо рассмотреть еще один способ, помогающий читать числовые строки. Как известно, метод println () предоставляет удобные средства для вывода на консоль различных типов данных, в том числе целых чисел и чисел с плавающей точкой. Он автоматически преобразует числовые значения в удобную для чтения форму. Но в Java отсутствует метод, который читал бы числовые строки и преобразовывал бы их во внутреннюю двоичную форму. Например, не существует варианта метода read (), который читал бы числовую строку "100" и автоматически преобразовывал ее в целое число, пригодное для хранения в переменной типа int. Но для этой цели в Java имеются другие средства. И проще всего подобное преобразование осуществляется с помощью так называемых оболочек типов.
Оболочки типов в Java представляют собой классы, которые инкапсулируют простые типы. Оболочки типов необходимы, поскольку простые типы не являются объектами, что ограничивает их применение. Так, простой тип нельзя передать методу по ссылке. Для того чтобы исключить ненужные ограничения, в Java были предусмотрены классы, соответствующие каждому из простых типов.
Оболочками типов являются классы Double, Float, Long, Integer, Short, Byte, Character и Boolean. Эти классы предоставляют обширный ряд методов, позволяющих полностью интегрировать простые типы в иерархию объектов Java. Кроме того, в классах-оболочках числовых типов содержатся методы, предназначенные для преобразования числовых строк в соответствующие двоичные эквиваленты. Эти методы приведены ниже. Каждый из них возвращает двоичное значение, соответствующее числовой строке. Оболочка типа Метод преобразования Double static double parseDouble(String str) throws NumberFormatException Float static float parseFloat(String str) throws NumberFormatException Long static long parseLong(String str) throws NumberFormatException Integer static int parselnt(String str) throws NumberFormatException Short static short parseShort(String str) throws NumberFormatException Byte static byte parseByte(String str) throws NumberFormatException
Оболочки целочисленных типов также предоставляют дополнительный метод синтаксического анализа, позволяющий задавать основание системы счисления.
Методы синтаксического анализа позволяют без труда преобразовать во внутренний формат числовые значения, введенные в виде символьных строк с клавиатуры или из текстового файла. Ниже приведен пример программы, демонстрирующий применение для этих целей методов parselnt () и parseDouble (). В этой программе находится среднее арифметическое ряда чисел, введенных пользователем с клавиатуры. Сначала пользователю прелагается указать количество числовых значений для обработки, а затем программа вводит числа с клавиатуры, используя метод readLine (), а с помощью метода parselnt () преобразует символьную строку в целочисленное значение. Далее осуществляется ввод числовых значений и последующее их преобразование в тип double с помощью метода parseDouble (). /* Эта программа находит среднее арифметическое для ряда чисел, введенных пользователем с клавиатуры. */ import java.io.*; class AvgNums { public static void main(String args[]) throws IOException { // создать объект типа BufferedReader, // использующий поток ввода System.in BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str; int n; double sum = 0.0; double avg, t; System.out.print("How many numbers will you enter: "); str = br.readLine(); try { // Преобразование символьной строки // в числовое значение типа int. n = Integer.parselnt(str); } catch(NumberFormatException exc) { System.out.println("Invalid format"); n = 0; } System.out.println("Enter " + n + " values."); for(int i=0; i < n ; i++) { System.out.print(" : "); str = br.readLine(); try { // Преобразование символьной строки // в числовое значение типа double, t = Double.parseDouble(str) ; } catch(NumberFormatException exc) { System.out.println("Invalid format"); t = 0.0; } sum += t; } avg = sum / n; System.out.println("Average is " + avg); } }
Выполнение этой программы может дать, например, следующий результат: How many numbers will you enter: 5 Enter 5 values. : 1.1 : 2.2 : 3.3 : 4.4 : 5.5 Average is 3.3
Пример для опробования 10.2. Создание справочной системы, находящейся на диске
В примере для опробования 4.1 был создан класс Help, позволяющий отображать сведения об операторах Java. Справочная информация хранилась в самом классе, а пользователь выбирал требуемые сведения из меню. И хотя такая справочная система выполняет свои функции, подход к ее разработке был выбран далеко не самый лучший. Так, если требуется добавить или изменить какие-нибудь сведения в подобной справочной системе, придется внести изменения в исходный код программы, которая ее реализует. Кроме того, выбирать пункт меню по его номеру не очень удобно, а если количество пунктов велико, то такой способ оказывается вообще непригодным. В этом проекте предстоит устранить недостатки, имеющиеся в справочной системе, разместив справочную информацию на диске.
В новом варианте справочная информация должна храниться в файле. Это будет обычный текстовый файл, который можно изменять, не затрагивая исходный код программы. Для того чтобы получить справку по конкретному вопросу, следует ввести название темы. Система будет искать соответствующий раздел в файле. Если поиск завершится успешно, справочная информация будет выведена на экран.
Последовательность действий
Создайте файл, в котором будет храниться справочная информация и который будет использоваться в справочной системе. Это должен быть обычный текстовый файл, организованный следующим образом: ``` название_темы_1
Информация по теме название_темы_2
Информация по теме название_темы_N
Информация по теме 2. Название каждой темы располагается в отдельной строке и предваряется символом #. Наличие специального символа в строке (в данном случае – #) позволяет программе быстро найти начало раздела. Под названием темы может располагаться любая справочная информация. После окончания одного раздела и перед началом другого должна быть введена пустая строка. Кроме того, в конце строк не должно быть лишних пробелов. 3. Ниже приведен пример простого файла со справочной информацией, который можно использовать вместе с новой версией справочной системы. В нем хранятся сведения об операторах Java. if
if(condition) statement; else statement; switch
switch(expression) { case constant: statement sequence break; // ... } for
for(init; condition; iteration) statement; while
while(condition) statement; do
do { statement; } while (condition); break
break; or break label; continue
continue; or continue label; 4. Присвойте этому файлу имя helpfile.txt. 5. Создайте файл FileHelp.java. 6. Начните создание новой версии класса Help со следующих строк кода: