Java. Полное руководство. 8-е издание. С. Н. Тригуб Перевод с английского и редакция
Скачать 25.04 Mb.
|
File f = new F i l e ("/autoexec.b a t "); Filelnputstream fl = new Filelnputstream(f Хотя первый конструктор, вероятно, используется чаще, второй позволяет подробно исследовать файл с помощью методов класса File, прежде чем присоединять его к входному потоку. При создании объект класса Filelnputstream открывается также и для чтения. Класс Filelnputstream переопределяет шесть методов абстрактного класса InputStream. Методы mark () и reset () не переопределяются, и все попытки использовать метод reset () с объектом класса Filelnputstream приводят к передаче исключения Следующий пример показывает, как прочесть один байт, массив байтов и диапазон из массива байтов. Также он иллюстрирует использование метода avail able () для определения оставшегося количества байтов, а также метода skip () — для пропуска нежелательных байтов. Программа Читает свой собственный исходный файл, который должен присутствовать в текущем каталоге. Обратите внимание на то, что здесь используется новый оператор 7 try-с-ресурсами для автоматического закрытия файла, когда он больше ненужен Глава 19. Ввод-вывод: пакет java.io 6 0 7 // Демонстрация применения FilelnputStream. // Эта программа использует оператор try-с-ресурсами. Требует JDK 7. import java.io.*; class FilelnputStreamDemo { public static void main(String a r g s []) { int size; // Для закрытия потока используется try-с-ресурсами. try ( FilelnputStream f = new FilelnputStream("FilelnputStreamDemo.java") ) { System.out.println("Total Available Bytes: " + (size = f .available())); int n = size/40; System.out.println("First " + n + " bytes of the file one read() at a t ime") ; for (int i=0; i < n; i++) { System.o u t .p r i n t ((char) f .r e a d ()); } System.out.println("\nStill Available: " + f .available()); System.out.println("Reading the next " + n + " with one read(b[])"); byte b[] = new byte[n]; if (f.read(b) != n) { System.err.println("couldn't read " + n + " bytes."); } System.out.println(new String(b, 0, n ) ); System.out.println("\nStill Available: " + (size = f .available())); System.out.println("Skipping half of remaining bytes with s k i p ()"); f .skip(size/2); System.out.println("Still Available: " + f .available()); System.out.println("Reading " + n/2 + " into the end of array"); if (f.read(b, n/2, n/2) i= n/2) { System.err.println("couldn7t read " + n/2 + " bytes."); } System.out.println(new String(b, 0, b.length)); System.out.println("\nStill Available: " + f .available()); } c a tch(IOException e) { System.out.println("I/O Error: " + e) Так выглядит вывод этой программы Available Bytes: 1785 First 44 bytes of the file one r e a d () at a time // Demonstrate FilelnputStream. // This pr 6 0 8 Часть II. Библиотека Java Still Available: 1741 Reading the next 44 with one read(b[]) ogram uses try-with-resources. It requires J Still Available: 1697 Skipping half of remaining bytes with s k i p () Still Available: 849 Reading 22 into the end of array ogram uses try-with-rebyte[n]; if ( Still Available: Этот несколько надуманный пример демонстрирует чтение тремя способами, пропуск ввода и проверку количества доступных данных в потоке. На заметку Этот и другие примеры этой главы обрабатывают все исключения ввода-вывода, которые могли бы произойти, как описано в главе 13. (Более подробная информация по этой теме приведена в главе Класс F i l e O u t p u t S t r e a Класс FileOutputStream создает объект класса OutputStream, который вы можете использовать для записи байтов в файл. Он реализует интерфейсы AutoCloseable, Closeable и Flushable. Вот четыре его наиболее часто используемых конструктора путькфайлу) FileOutputStream(File объектФайла) FileOutputStream(String путькфайлу, boolean добавить объектФайла, boolean добавить) Они могут передать исключение FileNotFoundException. Здесь пут ькф айлу— полное путевое имя файла, а объектФайла — объект класса File, описывающий файл. Если параметр добавить содержит значение true, файл открывается в режиме добавления. Создание объекта класса FileOutputStream не зависит оттого, существует ли указанный файл. Класс FileOutputStream создает его перед открытием, когда вы создаете объект. В случае попытки открытия файла, доступного только для чтения, будет передано исключение. В следующем примере создается буфер байтов. Сначала создается объект класса S t r i n g , а затем используется метод g e t B y t e s () для извлечения его эквивалента в виде байтового массива. Затем создается три файла. Первый — f i l e l . t x t — будет содержать каждый второй байт примера. Второй — f i l e 2 . t x t — полный набор байтов. Третий — f i l e 3 . t x t — будет содержать только последнюю четверть Демонстрация применения FileOutputStream. // Эта программа использует традиционный подход закрытия файла java.io.*; class FileOutputStreamDemo { public static void main(String a r g s []) { 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."; byte buf[] = source.getBytes(); FileOutputStream fO = null; FileOutputStream fl = null; Глава 19. Ввод-вывод: пакет java.io 6 0 9 FileOutputStream f2 = null; try { fO = new FileOutputStream("filel.tx t "); fl = new FileOutputStream (" file2 . txt11) ; f2 = new FileOutputStream("file3.txt"); // запись в первый файл (int i=0; i < buf.length; i += 2) fO.write(buf[i]); // запись во второй файл f1 .write(buf); // запись в третий файл .write(buf, b u f .length-buf.length/4, b u f .length/4); } c a t c h (IOException e) { System.out.println("An I/O Error Occurred"); } finally { try { if(f0 1= null) fO.closeO; } c a t c h (IOException e) { System.out.println("Error Closing filel.txt"); } try { if(fl ! = null) fl.closeO; } c a t c h (IOException e) { System.out.println("Error Closing file2.txt"); } try { if(f2 != null) f2.c l o s e (); } c a t c h (IOException e) { System.out.println("Error Closing Так будет выглядеть содержимое каждого файла после выполнения этой программы. Сначала будет представлен файл f i l e l . t x t . Nwi h iefralgo e t oet h i ftercuty n a hi u Затем файл file2.txt. Now is the time for all good men to come to the aid of their country and pay their due И наконец, файл f i l e 3 . t x t . nd pay their due Как видно из комментариев вверху, приведенная выше программа демонстрирует пример использования традиционного подхода закрытия файла, когда он больше ненужен. Этот подход применялся всеми версиями Java дои широко используется в устаревшем коде. Как можно заметить, здесь есть немного довольно неуклюжего кода, требуемого для явного вызова метода c l o s e (), поскольку каждый его вызов может передать исключение I O E x c e p t i o n , если операция закрытия потерпит неудачу. Эта программа может быть существенно улучшена при использовании нового оператора t r y -с ресурсами Вот, для сравнения, его переделанная версия. Обратите внимание она намного короче и понятнее Демонстрация применения FileOutputStream. // Эта программа использует оператор try-с-ресурсами. Требует JDK 7. 20 Зак 303 0 6 1 Часть II. Библиотека Java import java.io.*; class FileOutputStreamDemo { public static void main(String a r g s []) { 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."; byte b u f [] = source.getBytes(); // Использование Тгу-с-ресурсами для закрытия файлов try (FileOutputStream f0 = new FileOutputStream("filel.txt") , FileOutputStream fl = new FileOutputStream("file2.txt"), FileOutputStream f2 = new FileOutputStream("file3.tx t ") { // запись в первый файл (int i=0; i < buf.length; i += 2) fO.write(buf[i ]); // запись во второй файл f1 .write(buf); // запись в третий файл .write(buf, b u f .length-buf.length/4, b u f .length/4); } c a tch(IOException e) { System.out.println("An I/O Error Класс B y t e A r r a y I n p u t S t r e a Класс By teArray Input St ream реализация входного потока, использующего байтовый массив в качестве источника данных. Этот класс имеет два конструктора, каждый из которых требует байтового массива в качестве источника данных массив ]) ByteArraylnputStream(byte массив ], int начало int колБайтов) Здесь массив источник данных. Второй конструктор создает объект класса InputStream из подмножества байтового массива, который начинается с символа в позиции, указанной в начало, и длиной колБайт ов. Метод close () не имеет никакого влияния на класс ByteArraylnputStream. Поэтому нет необходимости вызывать метод close () для объекта класса ByteArraylnputStream, но ошибкой это не будет. В следующем примере создается пара объектов класса ByteArraylnputStream, которая инициализируется байтами, представляющими английский алфавит Демонстрация применения ByteArraylnputStream. import java.io.*; class ByteArraylnputStreamDemo { public static void main(String a r g s []) throws IOException { String tmp = "abcdefghijklmnopqrstuvwxyz"; byte b[] = t m p .getBytes(); ByteArraylnputStream inputl = new ByteArraylnputStream(b); ByteArraylnputStream input2 = new ByteArraylnputStream(b,0,3); } } Глава 19. Ввод-вывод: пакет java.io 6 1 Объект input 1 содержит полный алфавит в нижнем регистре, в то время как объект input2 — только первые три буквы. Класс ByteArraylnputStream реализует методы mark () и reset (). Однако если метод mark () не вызывается, то метод reset () устанавливает указатель потока в его начало — в начало байтового массива, переданного конструктору. Следующий пример показывает, как использовать метод reset () для чтения одного итого же ввода дважды. В этом случае программа читает и выводит буквы " abc 11 сначала в нижнем регистре, а затем в верхнем java.io.*; class ByteArraylnputStreamReset { public static void main(String a r g s []) { String tmp = "abc"; byte b[] = t m p .getBytes(); ByteArraylnputStream in = new ByteArraylnputStream(b); for (int i=0; i<2; i++) { int с ; while ((c = in.read()) != -1) { if (i == 0) { System.out.print((char) c ) ; } else { System.out.print(Character.toUpperCase((char) c ) ); } } System.out.println(); i n .r e s e t (Код в этом примере сначала читает каждый символ потока и печатает его, как он есть, — в нижнем регистре. Затем он сбрасывает потоки начинает чтение заново, на этот раз преобразуя перед выводом каждый символ в верхний регистр. Вывод получается таким. abc ABC Класс B y t e A r r a y O u t p u t S t r e a Классе это реализация потока вывода, использующего байтовый массив в качестве места назначения. Класс ByteArrayOutputStream имеет два конструктора, показанных ниже колБайтов) В первой форме создается буфер в 32 байт. Во втором создается буфер указанного в параметре колБайтов размера. Буфер хранится в защищенном поле buf класса ByteArrayOutputStream. Размер буфера увеличивается автоматически по мере необходимости. Количество байтов, содержащихся в буфере, хранится в защищенном поле count класса Метод close () не имеет никакого влияния накласс ByteArrayOutputStream. Поэтому нет необходимости вызывать его для объекта класса ByteArrayOutput Stream, но ошибкой это не будет. В следующем примере демонстрируется использование класса ByteArray OutputStream. 6 1 2 Часть II. Библиотека Java // Демонстрация применения ByteArrayOutputStream. // Эта программа использует оператор try-с-ресурсами. Требует JDK 7. import java.io.*; class ByteArrayOutputStreamDemo { public static void main(String a r g s []) { ByteArrayOutputStream f = new ByteArrayOutputStream(); String s = "This should end up in the array"; byte buf[] = s .getBytes(); try { f.write(buf); } c a t c h (IOException e) { System.out.println("Error Writing to Buffer"); return; } System.out.println("Buffer as a string"); System.out.println(f .toString() ) ; System.out.println("Into array"); byte b[] = f .toByteArray(); for (int i=0; i + +) System.out.p r i n t ((char) b[i]); System.out.println("\nTo an OutputStream()"); // Использование Try-с-ресурсами для управления // файловыми потоками ( FileOutputStream f2 = new FileOutputStream("test.tx t ") ) { f .wri t e T o (f2); } c a tch(IOException e) { System.out.println("I/O Error: " + e) ; return; } System.out.println("Doing a reset"); f .res e t (); for (int i=0; i\<3; i++) f.write('X '); System.out.println(f Запустив эту программу, вы получите следующий вывод. Обратите внимание после вызова метода r e s e t () выводится вначале три буквы ' X '. Buffer as a string This should end up in the array Into array This should end up in the array To an OutputStream() Doing a reset В этом примере для записи содержимого файла t e s t . t x t используется удобный метод w r i t e T o ( ) . Просмотр файла t e s t . t x t , созданного в предыдущем примере, покажет результат, который следовало ожидать should end up in the array Глава 19. Ввод-вывод: пакет java.io 6 1 Фильтруемые потоки байтов Фильтруемые потоки байтов — это просто оболочки вокруг входных или выходных потоков, обеспечивающие некоторые дополнительные функциональные возможности. Эти потоки обычно доступны методам, которые ожидают обобщенного потока, являющегося суперклассом фильтрованного потока. Типичными расширениями являются буферизация, преобразование символов и базовых данных. Фильтруемые потоки байтов это F i 1 1 e r l n p u t S tr e a m и F i l t e r O u t p u t S tr e a m . Их конструкторы показаны ниже os) FilterlnputStream(Inputstream Методы, представленные в этих классах, идентичны методам классов I n p u t s t r e a m и O u tp u tS t r e a m . Буферизуемые потоки байтов Для байтовых потоков буферизованные потоки расширяют класс фильтруемого потока, добавляя к нему буфер в памяти. Этот буфер позволяет Java выполнять операции ввода-вывода более чем по одному байту зараз, тем самым повышая производительность. Благодаря доступности буфера, возможны пропуск, маркировка и сброс потока. Буферизованные байтовые потоки имеют классы B uf f e r e d l n p u t S t r e a m и B uf f e r e d O u t p u t S tre a m . Класс P u s h b a c k l n p u t S t re am также реализует буферизо ванный поток. Класс Bu f f ere dlnp utSt Буферизация ввода-вывода — очень распространенный способ оптимизации производительности. Класс B uf f e r e d l n p u t S t r e a m позволяет заключить в оболочку любой поток класса I n p u t s t r e a m и достичь увеличения производительности. Класс B u f f e r e d l n p u t S t r e a m имеет два конструктора входнойПоток) BufferedlnputStream(Inputstream входнойПоток, int размерБуфера) Первая форма создает буферизованный поток, использующий размер буфера по умолчанию. Во второй форме размер буфера указывается параметром разм ерБ уф ера Рекомендуется использовать размеры буфера, кратные размеру страницы памяти, дисковому блоку и т.п., — это окажет существенное положительное влияние на производительность. Однако, с другой стороны, это зависит от реализации. Необязательный размер буфера обычно зависит от принимающей операционной системы, объема доступной памяти и конфигурации машины. Чтобы добиться эффективного использования буферизации, необязательно погружаться вовсе эти сложности. Было бы неплохо установить размер буфера для потока ввода-вывода в 8192 байт или даже меньше. Таким образом, низкоуровневая система сможет читать блоки данных с диска или из сети и сохранять результат в вашем буфере. То есть, даже если вычитаете данные по одному байту из объекта класса I n p u t s t r e a m , то большую часть времени будете иметь дело с быстрой памятью. Следующий пример моделирует ситуацию, в которой мы можем использовать метод m a rk () для запоминания места во входном потоке, чтобы позднее вернуться к нему с помощью метода r e s e t ( ) . Этот пример разбирает поток, находя в нем конструкцию HTML, указывающую на символ авторских прав. Такая ссылка начинается с амперсанда (&), заканчивается точкой с запятой ( ;) и не содержит какие- либо внутренние пробелы. Пример ввода содержит два амперсанда, чтобы показать случай, когда метод r e s e t ( ) срабатывает, а когда — нет |