Java. Полное руководство. 8-е издание. С. Н. Тригуб Перевод с английского и редакция
Скачать 25.04 Mb.
|
InputStreamReader(InputStream потокВвода) Поскольку переменная System, in ссылается на объект класса InputStream, она должна быть использована как параметр потокВвода. Собрав все вместе, получим следующую строку кода, которая создает экземпляр класса Buf f eredReader, связанный с клавиатурой br = new После выполнения этого оператора объект br представляет собой символьный поток, подключенный к консоли через поток Syst em . Чтение символов Для чтения символа из объекта класса Buf f eredReader применяется метод read () . Ниже показана версия метода read ( ), которая будет использоваться read() throws Каждый раз, когда вызывается метод read () , он читает символ из входного потока и возвращает его как целочисленное значение. При достижении конца потока возвращается значение -1 . Как видите, метод может передать исключение IOException. В следующей программе демонстрируется применение метода read () для чтения символов с консоли до тех пор, пока пользователь не введет "q". Обратите внимание на то, что любые исключения ввода-вывода, которые могут быть созданы, просто передаются в метод main () . Такой подход распространен при чтении Зак 303 0 3 2 Часть I. Язык с консоли в простых примерах программ, таких как показаны в этой книге, нов более сложных приложениях вы можете обработать исключения явно Использование BufferedReader для чтения символов с консоли import j a v a .i ос Вводите символы, 'q' — для выхода читать символы do с = (char) с while(c != 'q ') Ниже показан пример запуска этой программы. Вводите символы 'q ' — для выхода. 123abcq 1 2 3 а b с q Этот вывод может выглядеть немного не так, как вы ожидали, потому что потоке ш . in является строчно-буферизованным по умолчанию. Это значит, что никакого ввода в действительности программе не передается до тех пор, пока небу дет нажата клавиша () лишь отчасти применимым для интерактивного консольного ввода. Чтение строк Чтобы прочесть строку с клавиатуры, используйте версию метода readLine (), который является членом класса Buf f eredReader. Его общая форма такова readLine() throws Как видите, он возвращает объект класса Следующая программа демонстрирует объект класса Buf f eredReader и метод readLine () . Программа читает и отображает строки текста до тех пор, пока вы не введете слово стоп Чтение строк с консоли с применением BufferedReader. import java.io.*; class BRReadLines { public static void main(String a r g s []) throws IOException { // Создать BufferedReader с использованием System.in BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str; Глава 13. Ввод-вывод, аплеты и другие темы 3 2 Вводите строки текста."); System.out.println("Введите 'стоп' для завершения do { str = b r .readLine(); System.out.println(str); } w h i l e (!s t r .equals("стоп")); } } В следующем примере создается крошечный текстовый редактор. В коде создается массив объектов класса String, а затем читаются строки текста с сохранением каждой строки в виде элемента массива. Чтение производится до 100 строк или до того, как будет введено слово стоп. Для чтения с консоли используется объект класса Buf f eredReader. // Крошечный редактор java.io.*; class TinyEdit { public static void main(String a r g s []) throws IOException { // Создать BufferedReader, используя System.in BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String s t r [] = new Вводите строки текста r Введите 'стоп' для завершения f o r (int i=0; i<100; i + +) { str[i] = b r .readLine(); i f (s t r [i стоп) break; } System.out.println("\пВот ваш файл отобразить строки for(int i=0; i<100; i++) стоп) Ниже показан пример запуска этой программы. Вводите строки текста. Введите 'стоп' для завершения. Это строка один. Это строка два делает работу со строками простой. Просто создайте объект String, стоп Вот ваш файл: Это строка один. Это строка два делает работу со строками простой. Просто создайте объект Запись консольного вывода Консольный вывод проще всего осуществлять с помощью описанных ранее методов print() Hprintln(), которые используются в большинстве примеров 3 2 Часть I. Язык этой книги. Эти методы определены в классе Stream который является типом переменной System, out). Даже несмотря на то, что поток System, out — байтовый, применение его для вывода в простых программах вполне оправдано. Тем не менее в следующем разделе описана его символьная альтернатива. Поскольку класс PrintStream описывает выходной потоки происходит от класса OutputStream, он также реализует низкоуровневый метод write () . То есть метод write () может применяться для записи на консоль. Простейшая форма метода write () , определенного в классе PrintStream, показана ниже write(int значениебайта) Этот метод запишет байт, переданный в параметре значениебайта. Хотя параметр значениебайта объявлен как целочисленный, записываются только 8 его младших бит. Вот короткий пример, использующий метод write () для вывода на экран буквы " Ас последующим переводом строки Демонстрация System.o u t .w r i t e (). class WriteDemo { public static void main(String a r g s []) { int b; b = ' A ' ; System.out.write(b); System.out.write('\ n 'Вам нечасто придется использовать метод w r i t e () для вывода на консоль хотя в некоторых ситуациях это и удобно, поскольку значительно проще применять для этого методы p r i n t () и p r i n t l n (Класс Хотя применение потока System, out для вывода на консоль допустимо, он, вероятно, лучше подходит для отладки или для примеров программ вроде тех, что приводятся в настоящей книге. Для реальных программ рекомендуемым способом записи на консоль является поток класса PrintWriter. Класс PrintWriter — это один из символьных классов. Применение такого класса для консольного вывода упрощает интернационализацию ваших программ. Класс Printwriter определяет несколько конструкторов. Один из тех, которые мы будем использовать, показан ниже потокВывода, boolean сбросПриНовойСтроке) Здесь потокВывода — объект класса OutputStream, а сбросПриНовойСтроке управляет тем, будет ли Java сбрасывать буфер в выходной поток каждый раз при вызове метода print In () . Если значение сбросПриНовойСтроке равно true, то происходит автоматический сброс буфера, если же false, то нет. Класс Printwriter поддерживает методы print ( ) и println () . То есть вы можете использовать эти методы таким же способом, как они применяются в потоке System, out. Если аргумент непростого типа, то объект класса Printwriter вызывает метод toString(),a затем выводит результат. Чтобы писать на консоль с помощью объекта класса Printwriter, укажите поток Syst e m . out в качестве выходного потока и сбрасывайте поток после каждого символа новой строки. Например, следующая строка кода создает объект класса Printwriter, который подключен к консольному выводу Глава 13. Ввод-вывод, аплеты и другие темы 2 5 PrintWriter pw = new PrintWriter(System.o u t , Показанное ниже приложение иллюстрирует применение класса P r i n t W r i t e r для управления консольным выводом Демонстрация PrintWriter import java.io.*; public class PrintWriterDemo { public static void main(String a r g s []) { PrintWriter pw = new PrintWriter(System.out, true); p w Это строка int i = -7; pw.println(i ); double d = 4.5e-7; Вывод этой программы будет выглядеть следующим образом. Это строка -7 4.5Е-7 Помните, что нет ничего неправильного в применении потока System, out для простого текстового вывода на консоль, когда вы изучаете язык Java или занимаетесь отладкой своих программ. Однако класс PrintWriter обеспечивает возможность простой интернационализации для реальных программ. Поскольку никаких выгод от использования класса PrintWriter в простых программах нет, мы продолжим пользоваться потоком System. out для вывода на консоль. Чтение и запись файлов Язык Java предоставляет множество классов и методов, которые позволяют вам читать и записывать файлы. Прежде чем мы начнем, следует сказать, что тема ввода-вывода в файл весьма обширна подробно она исследуется в части II. Задача этого разделав том, чтобы познакомить вас с основными технологиями чтения из файла и записи в него. Хотя используются байтовые потоки, эти технологии можно адаптировать к символьным потокам. Два наиболее часто используемых потоковых класса — это классы Filelnput- Stream и FileOutputStream, которые создают байтовые потоки, связанные с файлами. Чтобы открыть файл, вы просто создаете объект одного из этих классов, указав имя файла в качестве аргумента конструктора. Хотя оба класса имеют и дополнительные конструкторы, мы будем использовать только следующие имяФайла) throws FileNotFoundException FileOutputStream(String имяФайла) throws Здесь имяФайла — имя файла, который вы хотите открыть. Если при создании входного потока файл не существует, передается исключение File NotFoundExcept ion. Для выходных потоков, если файл не может быть открыт или создан, также передается исключение FileNotFoundExcept ion. Класс исключения FileNotFoundExcept ion происходит от класса IOException. Когда выходной файл открыт, любой ранее существовавший файл стем же именем уничтожается 3 2 Часть I. Язык На заметку В ситуациях, где присутствует менеджер безопасности, некоторые файловые классы, включая классы Filelnputstream и FileOutputStream, передают исключение SecurityException, если при попытке открыть файл произойдет нарушение безопасности. По умолчанию приложения, запущенные при помощи команды java, не используют менеджер безопасности. Поэтому примеры ввода-вывода в этой книге не обязаны отслеживать возможность передачи исключения SecurityException. Однако другие типы приложений (такие, как аплеты) будут использовать менеджер безопасности и их файловый ввод-вывод вполне может создать исключение SecurityException. В таком случае выбудете должны соответственно обработать и это исключение. Когда вы завершаете работу с файлом, его необходимо закрыть. Для этого используется метод close(), реализованный в классах Filelnputstream и FileOutputStream, как показано ниже close() throws Закрытие файла высвобождает выделенные для него системные ресурсы, позволяя использовать их для других файлов. Неудача закрытия файла может привести к утечке памяти, поскольку неиспользуемые ресурсы останутся зарезерви рованы. На заметку Начиная с JDK 7 метод close () определяется интерфейсом AutoCloseable в пакете java. lang. Интерфейс AutoCloseable унаследован интерфейсом Closeable в пакете java.io. Оба интерфейса реализуются потоковыми классами включая классы Filelnputstream и Следует заметить, что существует два основных подхода, которые вы можете использовать для закрытия файла, когда он больше ненужен. Первый — традиционный подход, при котором метод close () вызывается явно, когда файл больше ненужен. Этот подход используется всеми версиями Java дои потому находится во всем существующем коде. Второй подразумевает использование нового оператора с ресурсами добавленного в JDK 7. Он автоматически закрывает файл, когда он больше ненужен. При этом подходе нет никаких явных вызовов метода close () . Поскольку существуют миллионы строк кода, написанного до JDK 7, которые все еще используются и поддерживаются, важно знать и понимать традиционный подход. Поэтому начнем с него. Новый автоматизированный подход описывается в следующем разделе. Чтобы читать файл, вы можете применять версию метода read () , которая определена в классе Filelnputstream. Та, что мы будем использовать, выглядит так read() throws Всякий раз, когда вызывается этот метод, он читает единственный байт из файла и возвращает его как целое число. Метод read () возвращает значение -1 , когда достигнут конец файла. Метод может передать исключение В следующей программе метод read () используется для ввода и отображения содержимого файла с текстом ASCII. Имя файла указано в аргументе командной строки Отображение текстового файла. Чтобы использовать эту программу, укажите имя файла который хотите просмотреть. Например, чтобы просмотреть файл T E S T .T X T используйте следующую командную строку ShowFile TEST.TXT */ import java.io.*; Глава 13. Ввод-вывод, аплеты и другие темы 3 2 7 class ShowFile { public static void main(String a r g s []) { int i; FilelnputStream fin; // Сначала убедиться, что имя файла указано if(args.length != 1) Использование ShowFile Файл return; } // Попытка открыть файл try { fin = new FilelnputStream(args[0]); } catch(FileNotFoundException e) { System.out.println("He могу открыть файл return; } // Теперь файл открыт и готов к чтению Следующий код читает символы, пока не встретится EOF. try { do { i = fin.read(); if(i != -1) System.out.print((char) i ) ; } w h i l e (i != —1); } cat c h (IOException e) Ошибка чтения файла Закрыть файл try { fin.c l o s e (); } c a t c h (IOException e) { System.out.p r Ошибка закрытия файла"); } } } В программе обратите внимание на блок t r y / c a t c h , обрабатывающий ошибки ввода-вывода, которые могут произойти. Каждая операция ввода-вывода проверяется на исключения, и если исключение происходит, оно обрабатывается. В простых программах или коде примеров вполне обычна передача исключений ввода- вывода за пределы функции m ain (), как это делалось в предыдущих консольных примерах. Кроме того, в реальном коде иногда полезно позволить исключению распространиться на вызывающую подпрограмму, чтобы уведомить ее о неудаче операции ввода-вывода. Однако большинство примеров файлового ввода-вывода в этой книге обрабатывает все исключения ввода-вывода явно, для демонстрации. Хотя приведенный пример закрывает файловый поток после чтения файла, существует вариант, который зачастую полезен. Он подразумевает вызов метода c l o s e () в пределах блока f i n a l l y . При таком подходе все методы, которые получают доступ к файлу, содержатся в пределах блока t r y , а блок f i n a l l y используется для закрытия файла. Таким образом, независимо оттого как закончится блок t r y , файл будет закрыт. С учетом приведенного примера, вот как может быть переделан блок t r y , который читает файл 3 2 Часть I. Язык Java try { do { i = f i n .r e a d (); if(i != -1) System.out.print((char) i); } w h i l e (i != -1) ; } c a tch(IOException e) Ошибка чтения файла finally { // Закрыть файл при выходе из блока try. try { f in.c l ose(); } c a t c h (IOException e) { System.out.p r i Ошибка закрытия файла"); } } Хотя в данном случае это не проблема, одним из преимуществ такого подхода является то, что если обращающийся к файлу код прекращает работу из-за каких- либо несвязанных с вводом-выводом исключений, файл все равно будет закрыт блоком f i n a l l y Иногда проще заключить все части программы, которые открывают файл и получают доступ к его содержимому, в один блок t r y (вместо того чтобы разделять его на два, а затем использовать блрк f i n a l l y , чтобы закрыть файл. Вот, например, другой способ написать программу S h o w F ile . /* Отображение текстового файла. Чтобы использовать эту программу, укажите имя файла который хотите просмотреть. Например, чтобы просмотреть файл T E S T .T X T используйте следующую командную строку ShowFile Этот вариант заключает код, который открывает и получает доступ к файлу, в один блок Файл закрывает блок finally. */ import java.io.*; class ShowFile { public static void main(String a r g s []) { int i ; Filelnputstream fin = null; // Сначала убедиться, что имя файла указано if(args.length != 1) Использование ShowFile Файл return; } // Следующий код открывает файл, читает символы, пока не // встретится EOF, а затем закрывает файл в блоке finally, try { fin = new Filelnputstream(args[0]); do { i = fin.r e a d (); if(i != -1) System.out.print((char) i); Глава 13. Ввод-вывод, аплеты и другие темы 3 2 9 } w h i l e (i 1= -1); } catch(FileNotFoundException e) Файл не найден c a tch(IOException e) Произошла ошибка I/O"); } finally { // Закрыть файл в любом случае try { if (fin ! = null) fin.closeO; } c a t c h (IOException e) Ошибка закрытия файла"); } } } } О б рати те внимание на то, что при этом подходе объект f i n инициализирует ся значением n u l l . Затем, в блоке f i n a l l y , файл закрывается, только если объект f i n не содержит значение n u l l . Это работает потому, что объект f i n не будет содержать значение n u l l , только если файл был успешно открыт. Таким образом, метод c l o s e () не вызывается, если при открытии файла происходит исклю чение. П оследовательность операторов t r y / c a t c h e приведенном выше примере можно сделать более компактной. Поскольку класс исключения происходит от класса I O E x c e p tio n , его необязательно обрабатывать отдельно. Вот, например, переделанная последовательность операторов, устраняющая обработчик исключения. В данном случае отображается стандартное сообщение исключения, описывающее ошибку { |