Java. Полное руководство. 8-е издание. С. Н. Тригуб Перевод с английского и редакция
Скачать 25.04 Mb.
|
throws IOException final boolean readBoolean( ) throws IOException final int readlnt( ) throws В следующей программе демонстрируется использование классов DataOutput Stream и DatalnputStream. Глава 19. Ввод-вывод: пакет java.io 6 2 1 // Демонстрация применения DatalnputStream и DataOutputStream. // Эта программа использует оператор try-с-ресурсами. Требует JDK 7. import java.io.*; class DatalODemo { public static void main(String a r g s []) // Сначала запись данных try ( DataOutputStream dout = new DataOutputStream(new FileOutputStream("Test.da t ")) ) { d o u t .writeDouble(98.6); do u t .w r i telnt( 1000); d o u t .writeBoolean(true); } catch(FileNotFoundException e) { System.out.println("Cannot Open Output File"); return; } c a t c h (IOException e) { System.out.println("I/O Error: " + e ) ; } // Теперь прочитать данные назад try ( DatalnputStream din = new DatalnputStream(new Filelnputstream("Test.d a t ")) ) { double d = din.readDouble(); int i = d i n .readlnt(); boolean b = d i n Вот значения " + 'd + " " + i + " " + b) ; } catch(FileNotFoundException e) { System.out.println("Cannot Open Input File"); return; } c a t c h (IOException e) { System.out.println("I/O Error: " + e) Вывод приведен ниже. Вот значения 98.6 1000 Класс R a n d o m A c c e s s F Класс R an d o m A ccessF ile инкапсулирует файл произвольного доступа. Он не наследуется от класса In p u tS tre a m или O utp u tStream . Вместо этого qh реализует интерфейсы Dat a In p u t и D ataO u tp u t, которые определяют базовые методы ввода-вывода. Он также реализует интерфейсы A u to C lo se a b le и C lo s e a b le . Класс R an d o m A ccessF ile отличает его поддержка запросов на позиционирование, те. вы можете установить указатель файла в любое место в пределах этого файла. Этот класс включает следующие два конструктора объектФайла, String доступ) throws FileNotFoundException RandomAccessFile(String имяфайла, String доступ) throws Впервой форме объект Файла задает открываемый файл как объект класса F i l e . Во второй форме имя файла передается параметром имя файла. В обоих 6 2 2 Часть II. Библиотека случаях доступ определяет тип доступа. Если он равен " г ", то файл может быть прочитан, ноне может быть записан. Если " r w " , то файл открывается в режиме чтения-записи. Если же доступ равен " r w s ", то файл открывается для операций чтения-записи и каждое изменение данных файла или его метаданных немедленно записывается на физическое устройство. Метод seek () , показанный ниже, используется для установки текущей позиции указателя внутри файла seek(long новПоз) throws Здесь новП оз указывает новую позицию в байтах файлового указателя от начала файла. После вызова метода seek () следующая операция чтения или записи выполняется в этой новой позиции. Класс RandomAccessFile реализует стандартные методы ввода и вывода, которые вы можете использовать для чтения и записи файлов произвольного доступа. Кроме того, он включает несколько дополнительных методов. Одним из них является метод set Length () . Его сигнатура такова setLength(long длина throws Этот метод устанавливает длину вызывающего файла равной указанному значению длина Метод может использоваться для удлинения или укорачивания файла. Если файл удлиняется, его добавочная порция является неопределенной. Символьные потоки В то время как классы байтовых потоков предоставляют необходимые функциональные возможности для выполнения операций ввода-вывода любого типа, они не могут работать напрямую с символами Unicode. Поскольку одной из главных целей Java является поддержка философии написано однажды, выполняется везде, понадобилось включить поддержку прямого ввода-вывода для символов. В этом разделе обсудим несколько классов символьного ввода-вывода. Как уже объяснялось, в вершине иерархии символьных потоков находятся абстрактные классы Reader и Writer. С них и начнем. На заметку Как было сказано в главе 13, классы символьного ввода-вывода были добавлены в версии Java 1.1. По этой причине вы все еще можете встретить унаследованный код, использующий байтовые потоки там, где более целесообразно было бы применить символьные потоки. Работая с таким кодом, будет неплохо обновить его. Класс R e a d e Класс Reader — абстрактный класс, определяющий символьный потоковый ввод Java. Он реализует интерфейсы AutoCloseable, Closeable и Readable. Все методы этого класса (за исключением метода markSupported ( )) в случае ошибочных ситуаций передают исключение IOException. В табл. 19.4 представлен краткий обзор методов класса Таблица 19.4. Методы, определенные в классе R e a d e Метод Описание void close () Закрывает входной поток. Последующие попытки чтения передадут исключение IOException void mark ( int количСимволов ) Помещает метку в текущую позицию во входном потоке, которая остается корректной до тех пор, пока не будет прочитано количСимволов символов Глава 19. Ввод-вывод: пакет java.io 6 2 Окончание табл. Описание m a r k S u p p o r t e d () int read() int read(char буфер буфер буфер смещение коли ч Символов коли ч Символов Возвращает значение true, если поток поддерживает методы mark () и reset Возвращает целочисленное представление следующего доступного символа вызывающего входного потока. При достижении конца файла возвращает значение -Пытается прочитать доб уф ер символов в буфер biи возвращает количество успешно прочитанных символов. При достижении конца файла возвращает значение -Пытается читать символы в буфер и возвращает фактическое количество успешно прочитанных символов. При достижении конца файла возвращает значение -Пытается прочитать док о ли ч Символов biсимволов в буфер biначиная с буфер смещение возвращает количество успешно прочитанных символов. При достижении конца файла возвращает значение -Возвращает значение true, если следующий запрос не будет ожидать. В противном случае возвращает значение Сбрасывает указатель ввода в ранее установленную позицию метки Пропускает коли ч Символов biсимволов ввода, возвращая количество действительно пропущенных символов Класс W r i t e Класс Writer — абстрактный класс, определяющий символьный потоковый вывод. Реализует интерфейсы AutoCloseable, Closeable, Flushable и Appendable. В случае ошибок все методы этого класса передают исключение IOException. Краткий обзор методов класса Writer представлен в табл. Таблица 19.5. Методы, определенные в классе w rite Метод Описание riter append(char символ символы riter append(CharSequence символы начало конец (Добавляет символ вконец вызывающего выходного потока. Возвращает ссылку на вызывающий поток Добавляет символы вконец вызывающего выходного потока. Возвращает ссылку на вызывающий поток Добавляет диапазон символы, заданный при помощи начало biи конец, вконец вызывающего выходного потока. Возвращает ссылку на вызывающий поток Закрывает вызывающий поток. Последующие попытки записи передадут исключение IOException 6 2 Часть II. Библиотека Метод void f l u s h () void write(int символ буфер буфер смещение коли ч Символов строка строка смещение коли ч Символ ов) Описание______________________________ - - Финализирует выходное состояние так, что все буферы очищаются. Иными словами, сбрасывает выходные буферы Записывает единственный символ в вызывающий выходной поток. Обратите внимание на то, что параметр имеет тип int, что позволяет вызывать метод w r i t e () с выражением без необходимости приведения обратно к типу char. Однако записываются только младшие 16 бит Записывает полный массив символов в вызывающий выходной поток Записывает диапазон коли ч С и м волов iсимволов из массива буфер, начиная с буфер смещение, в вызывающий выходной поток Записывает строка в вызывающий выходной поток Записывает диапазон коли ч Символов biсимволов из строки строка начиная с указанного смещения смещение Окончание табл. Класс F i l e R e a d e Это класс, производный от класса Reader, который вы можете использовать для чтения содержимого файла. Два наиболее часто используемых его конструктора выглядят так путькфайлу) FileReader(File объектФайла) Оба могут передать исключение FileNotFoundException. Здесь пут ькф айлу — полное путевое имя файла, а объектФайла — объект класса File, описывающий файл. Следующий пример показывает, как можно читать строки из файла и печатать их в стандартный выходной поток. Он читает собственный исходный файл, который должен находиться в текущем каталоге Демонстрация применения FileReader. // Эта программа использует оператор try-с-ресурсами. Требует JDK 7. import java.io.*; class FileReaderDemo { public static void main(String a r g s []) { try ( FileReader fr = new FileReader("FileReaderDemo.java") ) { int с ; // Читает и отображает файл = fr.read(J) != -1) System.out.print((char) c ) ; } c a t c h (IOException e) { Глава 19. Ввод-вывод: пакет java.io 6 2 5 System.out.println("I/O Error: " + Класс F i l e W r i t e Этот класс создает объект класса, производного от класса W r i t e r , который вы можете применять для записи файла. Рассмотрим его наиболее часто используемые конструкторы путькфайлу) FileWriter(String путькфайлу, boolean добавить объектФайла) FileWriter(File объектФайла, boolean добавить) Все они могут передавать исключение IO E x c e p tio n . Здесь пут ькф айлу — полное путевое имя файла, а объектФайла — объект класса F i l e , описывающий файл. Если добавить равно t r u e , то вывод добавляется вконец файла. Создание объекта класса F i l e W r i t e r не зависит оттого, существует ли файл. Класс F i l e W r i t e r создаст файл перед его открытием для вывода, когда вы создаете объект. В случае попытки открытия файла, доступного только для чтения, передается исключение I O E x c e p tio n Следующий пример представляет собой версию символьного потока из примера, представленного ранее, когда речь шла о классе F i le O u tp u t S tr e a m . Эта версия создает простой буфер символов, сначала создавая объект класса S t r i n g , а затем используя метод g e t C h a rs () для извлечения эквивалентного символьного массива. Затем она создает три файла. Первый файл, f i l e . t x t , будет содержать каждый второй символ примера. Второй файл, f i l e 2 . t x t , будет хранить полный набор символов. И наконец, третий файл, f i 1еЗ . t x t , будет содержать только последнюю четверть символов Демонстрация применения FileWriter. // Эта программа использует оператор try-с-ресурсами. Требует JDK 7. import java.io.*; class FileWriterDemo { public static void main(String a r g s []) throws IOException { String source = "Now is the time for all good men\n" + " to come to the aid of their country\n" + " and pay their due taxes."; char bu f f e r [] = new char[source.length()]; source.getChars(0, source.length(), buffer, 0); try ( FileWriter fO = new FileWriter("filel.txt"); FileWriter fl = new FileWriter("file2.txt"); FileWriter f2 = new FileWriter("file3.txt") ) { // запись в первый файл (int i=0; i < buffer.length; i += 2) { f0 .write(buffer[i]); } // запись во второй файл f1 .write(buffer); // запись в третий файл f2.write(buffer,buffer.length-buffer.length/4,buffer.length/4); 6 2 Часть II. Библиотека Java } c a t c h (IOException e) { S y s t e m . o u t . p r i n t l n ("An I/O Error Класс C h a r A r r a y R e a d e Класс CharArrayReader — реализация входного потока, использующего символьный массив в качестве источника. Этот класс имеет два конструктора, каждый из которых принимает символьный массив в качестве источника данных массив массив начало количСимволов) Здесь массив входной источник. Второй конструктор создает объект класса, производного от класса Reader, из подмножества символьного массива, начинающегося с символа в позиции, указанной параметром начало, и длиной коли чС им во лов. Метод close ( ), реализованный классом CharArrayReader, не передает исключений. Это связано стем, что он не может потерпеть неудачу. В следующем примере используется пара объектов класса CharArrayReader s. // Демонстрация применения Эта программа использует оператор try-с-ресурсами. Требует JDK 7. import java.io.*; public class CharArrayReaderDemo { public static void main(String a r g s []) { String tmp = "abcdefghijklmnopqrstuvwxyz"; int length = t m p .length(); char c[] = new c h a r [length]; t m p .getChars(0, length, c, 0) ; int i ; try (CharArrayReader inputl = new с )) { System.out.println("inputl:"); w h i l e ((i = inputl.r e a d ()) != -1) { System.out.print((char)i ); } System.out.println(); } cat c h (IOException e) { System.out.println("I/O Error: " + e ) ; } try (CharArrayReader input2 = new с , 0, 5)) { System.out.println("input2:"); while((i = input2.r e a d ()) != -1) { System.out.print((char)i) ; } System.out.println(); } c a t c h (IOException e) { System.out.println("I/O Error: " + e ) ; } } Глава 19. Ввод-вывод: пакет java.io 6 2 Объект input 1 создается из полного алфавита в нижнем регистре, в то время как объект input 2 содержит только первые пять букв. Вот вывод этой программы. input1: abcdefghijklmnopqrstuvwxyz input2: abcde Класс C h a r A r r a y W r i t e Класс CharArrayWriter — реализация выходного потока, использующего в качестве места назначения вывода массив. Класс CharArrayWriter имеет два следующих конструктора количСимволов) В первой форме создается буфер с размером по умолчанию. Второй буфер создается с размером, заданным параметром количС им волов Буфер находится в поле buf класса CharArrayWriter. Размер буфера будет при необходимости последовательно увеличиваться. Количество байтов, содержащихся в буфере, находится в поле count того же класса. Оба поля — buf и count — являются защищенными. Метод close () не имеет никакого влияния на класс В следующем примере демонстрируется использование класса CharArrayWriter в переделанной программе, рассмотренной ранее, когда речь шла о классе Byte ArrayOutputStream. Она приводит к тому же выводу, что и предыдущая версия Демонстрация применения CharArrayWriter. // Эта программа использует оператор try-с-ресурсами. Требует JDK 7. import java.io.*; class CharArrayWriterDemo { public static void main(String a r g s []) throws IOException { CharArrayWriter f = new CharArrayWriter(); String s = "This should end up in the array"; char buf[] = new c h a r [s .length()]; s . getChars ( 0 , s.lengthO, buf, 0) ; try { f.write(buf); } c a t c h (IOException e) { System.out.println("Error Writing to Buffer"); return; } Буфер в виде строки В массив с [] = f .toCharArray(); for (int i=0; i < c .length; i++) { System.out.print(c[i]); } System.out.println("\nB FileWriter()"); // Использование Тгу-с-ресурсами для управления // файловыми потоками ( FileWriter f2 = new FileWriter("test.t x t ") ) 6 2 Часть II. Библиотека Java { f,writeTo(f2) ; } c a t c h (IOException e) { S y s t e m . o u t . p r i n t l n ("I/O Error: " + e ) ; } S y s t e m . o u t . p r i n t l n (Выполнение r e s e t ()"); f .r e s e t (); for (int i=0; i<3; i++) f .w r i t e ('X '); S y s t e m . o u t . p r i n t l n (f .t o S t r i n g (Класс Класс Buf f e r e d R e a d e r увеличивает производительность за счет буферизации ввода. У него имеются два конструктора e a d e r ( R e a d e r входнойПоток) Buffere d R e a d e r ( R e a d e r входнойПоток, int размерБуфера) Первая форма создает буферизованный символьный поток, используя размер буфера по умолчанию. Во второй форме размер буфера задает размерБуфера. Закрытие объекта класса Buf f e r e d R e a d e r приводит к закрытию также внутреннего потока, определенного аргументом входнойПот ок. Как ив случае с байтовым потоком, буферизованный символьный входной поток также обеспечивает фундамент для поддержки перемещения обратно по потоку в пределах доступного буфера. Для обеспечения этого класс Buf f e re d R e a d e r реализует методы mark () и r e s e t ( ) , а метод Buf f e r e d R e a d e r .m a rk S u p p o r t ed () возвращает значение tr u e Следующий пример представляет собой переработанную версию примера с классом Buf f e r e d l n p u t S t r e a m , показанную выше, но использует символьный поток класса Buf f e re d R e a d e r вместо буферизованного байтового потока. Как и ранее, он использует методы mark () и r e s e t () для разбора потока на предмет поиска конструкции HTML с символом авторских прав. Такая ссылка начинается с ампер санда (&) и заканчивается точкой с запятой ( ;) без внутренних пробелов. Пример ввода содержит два амперсанда, чтобы продемонстрировать случай, когда вызов метода r e s e t () происходит, а когда — нет. Вывод будет таким же, что и раньше Использование буферизованного ввода Этап рограмма использует оператор t r y -с-ресурсами. Требует JDK 7. import java.io.*; class BufferedRe a d e r D e m o { public static void ma i n ( S t r i n g args[]) throws IOException { String s = "This is a © copyright symbol " + "but this is © not.\n"; char buf[] = n ew c h a r [s .l e n g t h ()]; s .g e t C h a r s (0, s.length(), buf, 0); C h a r A r r ayReader in = n ew C h a r A r r a y R e a d e r ( b u f ); int с ; b ool e a n mar k e d = false; try ( B u fferedReader f = n ew B u f f e r e d R e a d e r (in) ) Глава 19. Ввод-вывод: пакет java.io 6 2 9 { whil e (с = f . r e a d O ) != -1) { switch(c) { case '&': if (Imarked) { f.mark(32); marked = true; } else { ma rk ed = false; } break; case ';': if (marked) { m a r k e d = false; System.out.print("(c)"); } else System, out .print: ( (char) c) ; break; case 1 1: if (marked) { m a r k e d = false; f .reset (); S y s t e m . o u t . p r i n t ("&"); } else S y s t e m . o u t . p r i n t ( (char) c ) ; break; d e f a u l t : if ('marked) S y s t e m . o u t . p r i n t ((char) c) ; break; } } } c a t c h (IOException e) { S y s t e m . o u t . p r i n t l n ("I/O Error: " + e ) Класс Класс Buf f e r e d W r ite r — это класс, производный от класса W riter, который буферизует вывод. Благодаря применению класса Buf feredWr i t e r , можно повысить производительность за счет снижения количества операций физической записи в выходное устройство. Класс Buf f e r e d W r ite r имеет следующие два конструктора u f f e r e d W r iter(Writer выходнойПоток) B u f f e r e dWriter(Writer выходнойПоток, int размерБуфера) Первая форма создает буферизованный поток, использующий буфер с размером по умолчанию. Во второй размер буфера передается в параметре размерБуфера. Класс Класс Push backR eader позволяет возвращать во входной поток один или более байтов. Это позволяет заглянуть во входной буфер. Вот два его конструктора u s hbackReader(Reader входнойПоток) P u s hbackReader(Reader входнойПоток, int размерБуфера) 6 3 Часть II. Библиотека Первая форма создает буферизованный поток, позволяющий втолкнуть один символ. Во второй форме размер буфера вталкивания передается в параметре размерБуфера. При закрытии объекта класса PushbackReader закрывается также внутренний поток, определенный аргументом входнойПоток. Класс PushbackReader предоставляет метод unread () , который возвращает один или более символов в вызывающий входной поток. Доступны три формы этого метода unread(int символ throws IOException void unread(char буфер буфер смещение int количСимволов) throws Первая форма вталкивает символ, переданный в параметре символ Этот символ будет первым, который затем вернет последующий вызов метода read (). Вторая форма возвращает в поток символы из буфер Третья форма вталкивает количСимволов символов, начиная со смещения смещение, в буфер При попытке возврата символа в полный буфер передается исключение Следующая программа представляет собой переделанный пример с классом PushbacklnputStream, в котором класс PushbacklnputStream заменен классом PushbackReader. Как и ранее, он показывает, как синтаксический анализатор языка программирования может использовать вталкивание в поток для обнаружения отличия между операциями сравнения (==) и присваивания (=). // Демонстрация применения u n r e a d O . // Эта программа использует оператор try-с-ресурсами. Требует JDK 7. import java.io.*; class PushbackReaderDemo { public static void main(String a r g s []) { String s = "if (a == 4) a = 0;\n"; char buf[] = new c h a r [s .length()]; s . getChars ( 0 , s.length(), buf, 0) ; CharArrayReader in = new CharArrayReader(buf); int с ; try ( PushbackReader f = new PushbackReader(in) ) { while ( (c = f.readO) != -1) { switch(c) { case '=': if ( (c = f.readO ) == ' = ' ) System.o u t .p r i n t (".e q ."); else { System.out.print("<-"); f .unread(c); } break; default: System.out.print((char) c ) ; break; } } c a tch(IOException e) { System.out.p r intln("I/O Error: " + e ) ; } Глава 19. Ввод-вывод: пакет java.io 6 3 Класс P r i n t w r i t e Класс Printwriter — по сути, символьная версия класса PrintStream. Он реализует интерфейсы Appendable, Closeable и Flushable. Класс Printwriter имеет несколько конструкторов. Для начала рассмотрим следующие конструкторы выходнойПоток) Printwriter(OutputStream выходнойПоток, boolean сбросПриНовойСтроке) Printwriter(Writer выходнойПоток) Printwriter(Writer выходнойПоток, boolean сбросПриНовойСтроке) Здесь выходнойПоток определяет открытый объект класса OutputStream, который примет вывод. Параметр сбросПриНовойСтроке управляет автоматическим выталкиванием буфера при каждом вызове методов println ( ) , printf () или format () . Если параметр сбросПриНовойСтроке содержит значение true, то происходит автоматическое выталкивание буфера. Если же этот параметр содержит значение false, то автоматического выталкивания не происходит. Конструкторы, которые не принимают параметра сбросПриНовойСтроке, автоматического выталкивания не подразумевают. Следующий набор конструкторов предоставляет простую возможность создания объекта класса Printwriter, который пишет свой вывод в файл выходнойФайл ) throws FileNotFoundException Printwriter(File выходнойФайл, String наборсимволов) throws FileNotFoundException, UnsupportedEncodingException Printwriter(String имяВыходногоФайла) throws FileNotFoundException Printwriter(String имяВыходногоФайла, String наборсимволов) throws FileNotFoundException, Они позволяют создать объект класса Printwriter на основе объекта класса File либо имени файла. В любом случае файл создается автоматически. Любой ранее существовавший файл стем же именем уничтожается. Будучи созданным, объект класса Printwriter направляет весь вывод в указанный файл. Вы можете задать кодировку символов, передав ее имя в параметре наборсимволов. Класс Printwriter предоставляет методы print () и println () для всех типов, включая тип Object. Если аргумент не относится к элементарному типу, то методы класса Printwriter вызывают метод toString () такого объекта, аза тем выводят его результат. Класс Printwriter также поддерживает метод pr int f () . Он работает точно также, как ив классе PrintStream, описанном ранее, — позволяя задать точный формат данных. Метод printf () для класса Printwriter объявлен следующим образом printf(String формСтрока, Object ... аргументы printf(Locale регион String формСтрока, Object ... аргументы) Первая версия пишет аргументы в стандартный вывод в формате, указанном в формСтрока , используя региональные данные по умолчанию. Вторая версия позволяет задать региональные данные. Обе возвращают вызывающий объект класса Метод format () также поддерживается. Его общие формы таковы format(String формСтрока, Object ... аргументы format(Locale регион String формСтрока, Object ... аргументы) Этот метод работает подобно методу print f (Класс Ранее (в Java SE 6) был добавлен класс Console. Он используется для чтения и записи информации на консоли, если таковая существует, и реализует интерфейс 6 3 Часть II. Библиотека Java Flushable. Класс Console, прежде всего, введен для удобства, поскольку большая часть его функциональных возможностей доступна через объекты System, in и System, out. Однако его применение позволяет упростить некоторые виды консольных итераций, особенно при чтении строк с консоли. Класс Console не поддерживает конструкторов. Его объект получают вызовом метода System, console (). static Если консоль доступна, возвращается ссылка на нее. В противном случае возвращается значение nul 1. Консоль не будет доступна во всех классах, поэтому если возвращается значение null, консольные операции ввода-вывода невозможны. Класс Console определяет методы, перечисленные в табл. 19.6. Обратите внимание на то, что методы ввода, такие как метод readLine () , передают исключение IOException, когда возникают ошибки ввода. Класс исключения IOError происходит от класса Error и означает сбой ввода-вывода, который происходит вне контроля вашей программы. То есть обычно вы не будете перехватывать исключение IOError. Откровенно говоря, если исключение IOError возникнет в процессе обращения к консоли, обычно это свидетельствует о катастрофическом сбое системы. Также обратите внимание на методы readPassword () , которые позволяют приложению считывать пароль, не отображая его на экране. Читая пароли, следует обнулять как массив, содержащий строку, введенную пользователем, таки массив, содержащий правильный пароль, с которым нужно сравнить первую строку. Это уменьшает шансы вредоносной программы получить пароль при помощи сканирования памяти. Таблица 19.6. Методы, определенные в классе C o n s o l e Метод Описание . ' , - > 4 ,-4 44 - v oid f l u s h () Console f o r m a t (String форм Строка аргументы ) Console p r i n t f (String форм Строка аргументы ) Reader r e a d e r () String r e a d L i n e () String readLine(String форм Строка аргументы ) c h a r [ ] r e a d P a s s w o r d (Выполняет физическую запись буферизованного вывода на консоль Выводит на консоль аргументы используя формат, указанный в формСтрока Выводит на консоль аргументы, используя формат, указанный в формСтрока Возвращает ссылку на объект класса, производного от класса Reader, соединенный с консолью Читает и возвращает строку, введенную с клавиатуры. Ввод прекращается нажатием клавиши null. В случае сбоя передается исключение Отображает строку приглашения, форматированную в соответствии с формСтрока и аргументы, затем читает и возвращает строку, введенную с клавиатуры. Ввод прекращается, когда пользователь нажимает клавишу null. В случае сбоя передается исключение Читает и возвращает строку, введенную с клавиатуры. Ввод прекращается нажатием клавиши null. В случае сбоя передается исключение IOError__________________ Глава 19. Ввод-вывод: пакет java.io 6 3 Окончание табл. Описание h a r [ ] r e a d P a s s w o r d (S t r i n g формСтрока, O b j e c t . . . аргументы r i n t w r i t e r w r i t e r (Отображает строку приглашения, форматированную в соответствии с формСтрока и аргументы, а затем читает и возвращает строку, введенную с клавиатуры. Ввод прекращается, когда пользователь нажимает клавишу I O E r r o r Возвращает ссылку на объект класса, производного от класса Writer, ассоциированный с консолью Рассмотрим пример, демонстрирующий класс C o n s o le в действии Демонстрация применения g a r g s []) { String str; Console con; // Получить ссылку на консоль con = S y s t e m . c o n s o l e (); // Если нет доступной консоли, выход if(con == null) return; // Прочесть строку и отобразить ее str = c o n Введите строку "Вот ваша строка %s\n", Вывод этого примера. Введите строку Это тест. Вот ваша строка Это тест. Сериализация Сериализация — это процесс записи состояния объекта в байтовый поток. Она удобна, когда нужно сохранить состояние вашей программы в области постоянного хранения, такой как файл. Позднее вы можете восстановить эти объекты, используя процесс десериализации. Сериализация также необходима в реализации дистанционного вызова методов (Remote M ethod Invocation — RMI). RMI позволяет объекту Java на одной машине обращаться к методу объекта Java на другой машине. Объект может быть применен как аргумент этого дистанционного метода. Посылающая машина сериализу ет объект и передает его. Принимающая машина десериализует его. (Подробнее о RMI будет рассказано в главе Предположим, что объект, подлежащий сериализации, ссылается на другие объекты, которые, в свою очередь, имеют ссылки на еще какие-то объекты. Такой набор объектов и отношений между ними формирует ориентированный граф. В этом графе могут присутствовать и циклические ссылки. Иными словами, объект X может содержать ссылку на объекта объект Y — обратную ссылку на X. Объекты также 6 3 Часть II. Библиотека могут содержать ссылки на самих себя. Средства сериализации и десериализации объектов устроены так, что могут корректно работать во всех этих сценариях. Если вы попытаетесь сериализовать объект, находящийся на вершине такого графа объектов, то все прочие объекты, на которые имеются ссылки, также будут рекурсивно найдены и сериализованы. Аналогично вовремя процесса десериализации все эти объекты и их ссылки корректно восстанавливаются. Ниже приведен обзор интерфейсов и классов, поддерживающих сериализацию. Интерфейс S e r i a l i z a b l Только объект, реализующий интерфейс S e r i a l i z a b l e , может быть сохранен и восстановлен средствами сериализации. Интерфейс не содержит никаких членов. Он просто используется для того, чтобы указать, что класс может быть сериализован. Если класс является сериализуемым, все его подклассы также сериализуемы. Переменные, объявленные как t r a n s i e n t , не сохраняются средствами сериа лизации. Не сохраняются также статические переменные. Интерфейс E x t e r n a l i z a b l Средства Java для сериализации и десериализации спроектированы так, что большая часть работы по сохранению и восстановлению состояния объекта выполняется автоматически. Однако бывают случаи, когда программисту нужно управлять этим процессом. Например, может оказаться желательным использовать технологии сжатия и шифрования. Интерфейс предназначен именно для таких ситуаций. И нтерфейс E x t e r n a l i z a b l e определяет следующие два метода readExternal(Objectlnput входнойПоток) throws IOException, ClassNotFoundException void writeExternal(ObjectOutput выходнойПоток) throws В этих методах входнойПоток — это байтовый поток, из которого объект может быть прочитана выходнойПоток — байтовый поток, куда он записывается. Интерфейс O b j e c t O u t p u Интерфейс Obj e c t O u t p u t расширяет интерфейсы A u t o C l o s e a b l e и D a ta - O u t p i t , поддерживает сериализацию объектов. Он определяет методы, показанные в табл. 19.7. Особо отметим метод w r i t e O b j e c t (). Он вызывается для сериализа ции объекта. В случае ошибок все методы этого интерфейса передают исключение O E x c e p tio n Таблица 19.7. Методы, определенные в интерфейсе o b j e c t O u t p u t Метод Описание void c l o s e (Закрывает вызывающий поток. Последующие попытки записи передадут исключение f l u s h () Финализирует выходное состояние, чтобы очистить все буферы. То есть все выходные буферы сбрасываются Глава 19. Ввод-вывод: naxeTjava.io 6 3 Окончание табл. Описание write (byte буфер write (byte буфер смещение колБайтов) void write(int b) void writeObject(Object объект) Записывает массив байтов в вызывающий поток Записывает диапазон колБайтов байт из массива буфер начиная с буфер [ смещение] Записывает одиночный байт в вызывающий поток. Из аргумента Ь записывается только младший байт Записывает объект объект в вызывающий поток Класс O b j e c t O u t p u t S t r e a Класс Obj e c t O u t p u t S t r e a m расширяет класс O u t p u t S t r e a m и реализует интерфейс O b j e c t O u t p u t . Этот класс отвечает за запись объекта в поток. Конструктор его выглядит так выходнойПоток) throws Аргумент выходнойПоток представляет собой выходной поток, в который могут быть записаны сериализуемые объекты. Закрытие объекта класса Obj e c t O u tp u tS tr e a m приводит к закрытию также внутреннего потока, определенного аргументом выходнойПоток. Несколько часто используемых методов класса перечислено в табл. 19.8. В случае ошибки все они передают исключение IO E x c e p t io n . Присутствует также класс P u t F i e l d , вложенный в класс Obj e c tO u tp u t S t r e a m . Он обслуживает запись постоянных полей, и описание его применения выходит за рамки настоящей книги. Таблица 19.8. Некоторые из наиболее часто используемых методов класса O b j e c t O u t p u t S t r e a Г' У V" Метод Описание void c l o s e () void f l u s h () void write (byte буфер буфер смещение колБайтов) void write(int b) void writeBoolean(boolean b) void w r i t e B y t e (int b) void w r i t e B y t e s (String строка w r i t e C h a r (int Закрывает вызывающий поток. Последующие попытки записи передадут исключение IOException. Внутренний поток тоже закрывается Финализирует выходное состояние, так что все буферы очищаются. То есть все выходные буферы сбрасываются Записывает массив байтов в вызывающий поток Записывает диапазон колБайтов байт из массива буфер начиная с буфер [ смещение] Записывает одиночный байт в вызывающий поток. Из аргумента b записывается только младший байт Записывает значение типа boolean в вызывающий поток Записывает значение типа byte в вызывающий поток. Записываемый байт — младший из аргумента Ь Записывает байты, составляющие строку str, в вызывающий поток Записывает значение типа char в вызывающий поток 6 3 6 Часть II. Библиотека Окончание табл. 19.8 «I Лг ’ г »%'-f •*- й <•***«* 1,4>г #«*£»■ Ц - « ’"■£* void w r i t e C h a r s (String строка writeDouble(double d) void w r i t e F l o a t (float f) void writelnt(int i) void writeLong(long 1) final void writeObject(Object объект Записывает символы, составляющие строку строка, в вызывающий поток Записывает значение типа double в вызывающий поток Записывает значение типа float в вызывающий поток Записывает значение типа int в вызывающий поток Записывает значение типа long в вызывающий поток Записывает объект объект в вызывающий поток Записывает значение типа short в вызывающий поток Интерфейс Obj ect Интерфейс расширяет интерфейсы AutoCloseable и Data lnput и определяет методы, перечисленные в табл. 19.9. Он поддерживает сериа лизацию объектов. Особо стоит отметить метод readObject (). Он вызывается для десериализации объекта. В случае ошибок все эти методы передают исключение IOException. Метод readObject () также может передать исключение Таблица 1 9 .9 . Методы, определенные в интерфейсе o b j e c t l n p u t Меток О яи и й ие int a v a i l a b l e () void c l o s e () int read() int read(byte буфер read(byte буфер смещение колБайтов) Obj ect readObj e c t () Long skip(long Возвращает количество байтов, которые доступны во входном буфере в настоящий момент Закрывает вызывающий поток. Последующие попытки чтения вызовут передачу исключения IOException. Внутренний поток тоже закрывается Возвращает целочисленное представление следующего доступного байта ввода. При достижении конца файла возвращается значение -Пытается прочитать доб уф ер длина байт в буфер , начиная с буфер [ смещение, возвращая количество байтов, которые удалось прочитать. При достижении конца файла возвращается значение -Пытается прочитать до кол Байтов байт в буфер начиная с буфер [ смещение, возвращая количество байтов, которые удалось прочитать. При достижении конца файла возвращается значение -Читает объект из вызывающего потока Игнорирует (те. пропускает) колБайтов байт вызывающего потока, возвращая количество действительно пропущенных байтов Глава 19. Ввод-вывод: пакет java.io 6 3 Класс O b j e c t I n p u t S t r e a Этот класс расширяет класс I при t S t г е аш и реализует интерфейсе с 11 при Класс Obj ect Input Stream отвечает зачтение объектов из потока. Ниже показан конструктор этого класса входнойПоток) throws Аргумент входнойП от ок — это входной поток, из которого должен быть прочитан сериализованный объект. Закрытие объекта класса Obj ect Input Stream приводит к закрытию также внутреннего потока, определенного аргументом входнойПоток. Несколько часто используемых методов этого класса показано в табл. 19.10. В случае ошибок все они передают исключение IOException. Метод readOb- ject() также может передать исключение ClassNotFoundException. Также в классе Obj ect InputStream присутствует вложенный класс по имени GetField. Он обслуживает чтение постоянных полей, и описание его применения выходит за рамки настоящей книги. Таблица 19.10. Часто используемые методы, определенные в классе ObjectlnputStream Метод Описание int a v a i l a b l e () v oid c l o s e () int read() int read(byte буфер смещение колБайтов) Boolean r e a d B o o l e a n () byte r e a d B y t e () char r e a d C h a r () double r e a d D o u b l e () double r e a d F l o a t () void readFully(byte буфер буфер смещение кол Байтов) Возвращает количество байтов, доступных в данный момент во входном буфере Закрывает вызывающий поток. Последующие попытки чтения вызовут передачу исключения IOException. Внутренний поток тоже закрывается Возвращает целочисленное представление следующего доступного байта ввода. При достижении конца файла возвращается значение -Пытается прочитать до кол Байтов байт в буфер b,bначиная с буфер [ смещение, возвращая количество байтов, которые удалось прочитать. При достижении конца файла возвращается значение -Читает и возвращает значение типа boolean из вызывающего потока Читает и возвращает значение типа byte из вызывающего потока Читает и возвращает значение типа char из вызывающего потока Читает и возвращает значение типа double из вызывающего потока Читает и возвращает значение типа float из вызывающего потока Читает буфер. длина байт в буфер. Возвращает управление, только когда все байты прочитаны Читает колБайтов байт в буфер, начиная с буфер [ смещение] Возвращает управление, только когда прочитано кол Байтов байт 6 3 Часть II. Библиотека Окончание табл. 19.10 Метод Описание int r e a d l n t (Читает и возвращает значение типа int из вызывающего потока r e a d L o n g (Читает и возвращает значение типа long из вызывающего потока Object Читает и возвращает объект из вызывающего потока r e a d S h o r t (Читает и возвращает значение типа short из вызывающего потока r e a d U n s i g n e d B y t e (Читает и возвращает значение типа unsigned byte из вызывающего потока r e a d U n s i g n e d S h o r t (Читает и возвращает значение типа unsigned short из вызывающего потока Пример сериализации В следующей программе показано, как использовать сериализацию и десериа лизацию объектов. Начинается она с создания экземпляра объекта MyClass. Этот объект имеет три переменные экземпляра типа String, int и double. Именно эту информацию мы хотим сохранять и восстанавливать. В программе создается объект класса FileOutputStream, который ссылается на файл по имении для этого файлового потока создается объект класса Obj ectOutputStream. Метод writeObject () этого объекта класса Obj ect OutputStream используется затем для сериализации объекта. Объект выходного потока очищается и закрывается. Далее создается объект класса Filelnputstream, который ссылается на файл по имении для этого файлового потока создается объект класса Obj ect InputStream. Метод readObj ect () класса Obj ect Input St ream используется для последующей десериализации объекта. После этого входной поток за крывается. О братите внимание на то, что объект MyClass определен с реализацией интерфейса. Если бы этого не было, передалось бы исключение NotSerializableException. Поэкспериментируйте с этой программой, объявляя некоторые переменные экземпляра MyClass как transient. Эти данные не будут сохраняться при сериализации. // Демонстрация сериализации // Эта программа использует оператор try-с-ресурсами. Требует JDK 7. import java.io.*; public class SerializationDemo { public static void main(String a r g s []) { // Сериализация объекта ( ObjectOutputStream objOStrm = new ObjectOutputStream(new FileOutputStream("serial")) ) { MyClass objectl = new M y C l a s s ("Hello", -7, 2.7el0); System.out.println("objectl: " + objectl); objOStrm.writeObject(objectl); Глава 19. Ввод-вывод: пакете) Исключение вовремя сериализации : " + е) ; } // Десериализация объекта ( ObjectlnputStream objIStrm = new ObjectlnputStream(new Filelnputstream("serial")) ) { MyClass object2 = (MyClass)objIStrm.readObject(); System.out.println("object2: " + object2); } catch(Exception e) { System-, o u t .println (Исключение вовремя сериализации: " + е) ; System.exit(0) ; } } } class MyClass implements Serializable { String s; int i; double d; public M y Class(String s, int i, double d) { this.s = s; this.i = i; this.d = d; } public String toString() { return "s=" + s + i=" + i + d=" + Эта программа демонстрирует идентичность переменных экземпляра объектов o b j e c t l и o b j e c t 2. Вот ее вывод s=Hello; i=-7; d=2.7ElO object2: s=Hello; i=-7; Преимущества потоков Потоковый интерфейс ввода-вывода в Java предоставляет чистую абстракцию для сложных и зачастую обременительных задач. Композиция классов фильтрующих потоков позволяет динамически строить собственные настраиваемые потоковые интерфейсы, которые отвечают вашим требованиям к передаче данных. Программы Java, использующие эти абстрактные высокоуровневые классы — I n p u t S t r e a m , O u tp u tS tr e a m , R e a d e r и W r i t e r , — будут корректно функционировать в будущем, даже когда появятся новые усовершенствованные конкретные потоковые классы. Как вы увидите в главе 21, эта модель работает очень хорошо, когда мы переключаемся от набора потоков на основе файлов к сетевым потоками потокам сокетов. И наконец, сериализация объектов играет важную роль в программах Java различных типов. Классы сериализации ввода-вывода Java обеспечивают переносимое решение этой непростой задачи <« |