system out java что это
Класс System в Java
Java предоставляет нам полный набор готовых классов и библиотек, что снижает необходимость в служебном кодировании. Одним из таких классов является класс System в Java.
Что такое класс System в Java?
Системный является одним из базовых классов в Java и принадлежит пакету java.lang. Класс System является финальным и не предоставляет общедоступных конструкторов. Из-за этого все члены и методы, содержащиеся в этом классе, являются статическими по природе.
Таким образом, вы не можете наследовать этот класс для переопределения его методов. Поскольку класс System имеет множество ограничений, существуют различные предварительно созданные поля и методы класса. Ниже я перечислил несколько важных функций, поддерживаемых этим классом:
Объявление
Поля класса
Класс java.lang.System поставляется с тремя полями:
Методы системного класса
Всего в классе java.lang.System объявлено 28 встроенных методов.
Метод | Описание |
---|---|
static void arraycopy (Object src, int srcPos, Object dest, int destPos, int length) | Помогает копировать массив из указанного исходного массива, начиная с указанной позиции до указанной позиции целевого массива. |
static String clearProperty (ключ String) | Помогает удалить системное свойство, указанное указанным ключом. |
Консоль static static () | Помогает вернуть любой доступный уникальный объект консоли, связанный с текущей JVM. |
статическое длинное currentTimeMillis() | Помогает вернуть текущее время в миллисекундах |
выход из статической пустоты (статус int) | Помогает завершить текущую JVM |
статическая пустота gc() | Этот метод помогает в запуске сборщика мусора |
статическая карта getenv() | Помогает в возврате неизменяемой строковой карты текущей системы |
static String getenv (имя строки) | Помогает в получении значения указанной переменной среды |
статические свойства getProperties () | Помогает в определении текущих свойств системы |
статическая строка getProperty (строковый ключ) | Помогает получить системное свойство, указанное указанным ключом. |
статическая строка getProperty (ключ строки, строка определения) | Помогает получить системное свойство, указанное указанным ключом. |
статический SecurityManager getSecurityManager () | Помогает получить интерфейс безопасности системы |
static int identityHashCode (Object x) | Помогает возвращать тот же хэш-код для данного объекта, значение которого будет похоже на метод по умолчанию hashCode (), независимо от переопределения класса данного объекта hashCode () |
статический Канал унаследованный канал () | Помогает в возврате канала, который унаследован от объекта, создавшего JVM. |
статическая строка lineSeparator () | Помогает в возврате системно-зависимой строки разделителя строк. |
статическая пустая нагрузка (строковое имя файла) | Помогает в загрузке файла кода с указанным именем файла из локальной файловой системы в виде динамической библиотеки. |
static void loadLibrary (строковое имя_библиотеки) | Помогает в загрузке системной библиотеки, указанной аргументом libname |
статическая строка mapLibraryName (строковое имя_библиотеки) | Помогает в отображении имени библиотеки в специфическую для платформы строку, представляющую собственную библиотеку |
статический длинный nanoTime () | Помогает возвращать текущее значение работающего источника времени высокого разрешения JVM в течение наносекунд |
static void runFinalization () | Помогает в выполнении методов завершения любых объектов, ожидающих завершения |
static void setErr (PrintStream err) | Помогает переназначить «стандартный» поток вывода ошибок |
статическая пустота setIn (InputStream in) | Помогает переназначить «стандартный» поток ввода |
static void setOut (PrintStream out) | Помогает переназначить «стандартный» поток вывода |
static void setProperties (Свойства реквизита) | Помогает в настройке системных свойств для аргумента Свойства |
статическая строка setProperty (строковый ключ, строковое значение) | Помогает в настройке системного свойства, указанного указанным ключом |
static void setSecurityManager (SecurityManager s) | Помогает в настройке безопасности системы |
static void runFi nalizersOnExit (логическое значение) | Устаревшее |
Реализация
В следующем примере я реализовал несколько из рассмотренных выше методов.
Вывод
Вы можете попробовать реализовать остальные методы, и если вы где-то застряли, вы можете оставить комментарий, и мы поможем вам с этим.
System out println java — консольный вывод
Содержание
В Java возможен вывод данных любого типа. Он реализуется при помощи строки кода System.out.println() в Java. Основная среда использования метода — служебные и демонстрационные программы. В других типах приложений не применяется, поскольку в них вывод осуществляется за счет графических пользовательских интерфейсов с выполнением других методов.
Что собой представляет метод
В Java есть потоки, за счет которых выполняется функция вывода. Каждый из них представляется как отдельная инструкция, порядок выполнения которой задает пользователь. Потоки — связующее звено между системами ввода-вывода и физическим устройством, поэтому принцип их действия одинаковый. Отличаются лишь применяемые к ним методы.
Обзор синтаксиса
Чтобы разобраться, как команда работает на Java, следует понять работу каждого отдельного компонента System.out.println().
System — класс, к которому команда будет обращаться при выполнении. Он инкапсулирует необходимые средства из классов, которые обеспечивают работу метода.
Out — переменная, которая предопределена классом Output и принимает поток. К ней обращается System. Он является экземпляром Output, поэтому имеет доступ ко всем его методам по принципам ООП.
Println() — экземпляр класса Outputstream, именуемый PrintStream. Он содержит инструкции, позволяющие обрабатывать данные, выводимые на экран. Сюда ссылается переменная out. Как и в любую функцию, сюда можно передавать аргументы.
Таким образом, для вывода строки Hello, Java-программа обращается к System, а тот, в свою очередь, к Output, а затем к PrintStream, которые являются экземплярами класса OutputStream и производят необходимые действия.
Примеры работы
Работу с методом можно обеспечить с помощью терминала ОС либо среды разработки. Перед этим создается проект и класс с одинаковыми названиями. В окне создания элемента можно поставить галочку на пункте главного метода. В результате получим код с необходимыми для работы данными. Введем в блок главного метода main пустую команду вывода на консоль.
В Java метод system out println может выводить разные типы данных. Чтобы вывести на экран строку, необходимо в пустых скобках как аргумент указать набор любых символов в кавычках.
Метод может передавать значения переменных любого типа. Для этого нужно ввести без кавычек название переменной откуда будет браться значение.
Также можно передать значение нескольких переменных и действий над ними вместе со строкой.
Такой код выведет результат сложения переменных и строк.
Приложив спецификаторы и escape-последовательности к system out println java, примеры можно реализовывать другим способом.
Здесь применяется спецификатор %d, который принимает значение указанных через запятую аргументов. В данном примере нет переноса строки. Его обеспечивает метод println(), в отличие от print() и printf(), которые не осуществляют перевода. Добиться этой функции возможно при помощи escape-последовательности \n. Ее необходимо добавить в строку через пробел в том месте, где нужен перенос.
System.out.println() в Java имеет свои списки escape-последовательностей и заимствованных из C++ спецификаторов.
Сокращенный ввод
Когда необходимо сократить время написания кода и избежать ошибок, помогают быстрые способы написания кода. Для того чтобы быстро выполнить сокращенный ввод System.out.println() на Java, необходимо ввести syso, нажать клавишу Enter. Выполняется это следующим образом.
При вводе краткой формы любой команды появляются всплывающие дополнения. Нажав на одно из них, система подставит нужный конец инструкции.
Таким образом, в Java реализованы все возможности вывода. Для того чтобы глобально их освоить, достаточно немного практики с применением всех изложенных возможностей.
Вывод и ввод данных в консоль Java
Консоль (console) в Java обеспечивает простое и удобное взаимодействия с пользователем. С помощью консоли можно выводить какую-нибудь информацию либо, напротив, используя консоль, считывать данные. В этой статье будет рассказано о том, как осуществляется ввод и вывод данных в консоли Java.
Чтобы обеспечивать взаимодействие с консолью, в языке программирования Java используют класс System.
Вывод на консоль в Java
Чтобы создать потока вывода в вышеупомянутый класс System, вам понадобится специальный объект out. В нём определен метод println, обеспечивающий вывод значения на консоль и перевод курсора консоли на другую строку.
Рассмотрим практический пример с Hello world:
Что здесь происходит? В метод println осуществляется передача значения (в нашем случае это строка), которое пользователь желает вывести в консоль Java. Консольный вывод данных в Джава будет следующий:
Вывод в консоли Java:
Однако никто не мешает, используя System.out.print, всё же выполнить перенос на следующую строку. Как вариант — использование \n:
Также есть возможность подставить в строку Ява данные, которые объявлены в переменных. Вот, как это реализуется:
Спецификаторы: • %d — для вывода в консоль целочисленных значений; • %x — для 16-ричных чисел; • %f — выводятся числа с плавающей точкой; • %e — для чисел в экспоненциальной форме (1.3e+01); • %c — вывод в консоль одиночного символа; • %s — вывод в консоль строковых значений.
Рассмотрим, как это функционирует на практике:
Когда осуществляется вывод в консоль Java значений с плавающей точкой, есть возможность задать количество знаков после запятой. Спецификатор %.2f (точнее, «.2») определяет, что будет 2 знака после запятой. Вывод в консоль Java будет следующим:
Ввод с консоли Java или как ввести данные с консоли Джавы
Чтобы обеспечить ввод с консоли Java, в классе System есть объект in. Именно через объект System.in работать не очень удобно, поэтому часто применяют класс Scanner. Он уже, в свою очередь, как раз таки и применяет System.in.
Рассмотрим практический пример:
Сам по себе класс Scanner хранится в пакете java.util, поэтому в начале кода мы выполняем его импорт посредством команды import java.util.Scanner.
Лучше всего попробовать работу этой программы с помощью одного из многочисленных онлайн-компиляторов.
Работать она будет простейшим образом: 1. Сначала вы увидите сообщение в консоли «Введите любой номер:». 2. После ввода числа (пускай это будет 8) в консоли появится второе сообщение — «Ваш номер: 8».
Для класса Scanner предусмотрены и другие методы: • next() — для считывания введённой строки до первого пробела; • nextLine() — для всей введённой строки; • nextInt() — считывает введённое число int; • nextDouble() — для double; • nextBoolean() — для boolean; • nextByte() — для byte; • nextFloat() — для float; • nextShort() — для short.
Давайте напишем простую программу, обеспечивающую ввод информационных данных о человеке в консоль Java:
В этой программке пользователь последовательно вводит данные разных типов: String, int и float. Потом вся информация выводится в консоль Java:
Вот и всё. Это базовые вещи, если же вас интересуют более продвинутые знания, записывайтесь на курс OTUS в Москве:
BestProg
Система ввода/вывода Java. Потоки. Байтовые потоки. Символьные потоки. Стандартные потоки
Содержание
Поиск на других ресурсах:
1. Общие понятия системы ввода/вывода Java. Поток. Определение потока
В языке программирования Java ввод/вывод информации базируется на понятии потока. Поток – это абстрактное понятие, которое символизирует источник или приемник данных, который может передавать или получать некоторую информацию. Любой поток скрывает операции над данными, которые выполняются на низших уровнях непосредственно в устройствах ввода/вывода.
Соответственно назначению потоков, классифицируются и классы в языке Java. Одни классы реализуют операции ввода, другие реализуют операции вывода. Чтобы использовать классы потоков ввода/вывода нужно импортировать пакет java.io
Объекты классов Java, которые используются для ввода/вывода, для обеспечения необходимой функциональности наслаиваются друг на друга. Такая модель взаимодействия объектов поддерживается в паттерне «Декоратор». В этом паттерне при создании потока нужно использовать несколько объектов.
2. Виды потоков в Java
В языке Java различают два вида потоков:
Классы, которые реализуют байтовые потоки ввода унаследованы от абстрактного класса InputStream :
Классы, которые реализуют байтовые потоки вывода унаследованы от абстрактного класса OutputStream :
4. Символьные потоки ввода/вывода. Обзор классов символьных потоков
Классы, которые предназначены для описания символьных потоков делятся на два вида:
Классы потоков ввода следующие:
Классы потоков вывода следующие:
11: Система ввода/вывода в Java
Создание хорошей системы ввода/вывода (I/O) является одной из наиболее сложных задач для разработчиков языка.
Доказательством этому служит наличие множества различных подходов. Сложность задачи видится в охвате всех возможностей. Не только различный исходный код и виды ввода/вывода, с которыми вы можете общаться (файлы, консоль, сетевые соединения), но так же вам необходимо общаться с ними большим числом способов (последовательный, в случайном порядке, буферный, бинарный, посимвольный, построчный, пословный и т.п.).
Эта глава даст вам введение в различные классы ввод/вывода стандартной библиотеки Java и расскажет о том, как их использовать.
Класс File
Прежде чем перейти к классам, которые действительно читают и записывают данные в поток, мы посмотрим на утилиты, обеспечивающиеся библиотекой в помощь вам в обработке директории файлов.
Список директории
DirFilter показывает, что из-за того, что interface содержит только набор методов, вы не ограничены в написании только этих методов. (Однако вы должны как минимум обеспечить определение для всех методов интерфейса.) В этом случае также создается конструктор DirFilter.
Метод accept( ) должен принимать объект File, представляющий директорий, в котором находится определенный файл, а String содержит имя этого файла. Вы можете выбрать использовать или игнорировать любой из этих аргументов, но вы, вероятно, как минимум, должны использовать имя файла. Помните, что метод list( ) вызывает метод accept( ) для каждого имени файла в директории, чтобы проверить, какой из них должен быть включен — на это указывает тип boolean результата, возвращаемого accept( ).
Метод list( ) возвращает массив. Вы можете опросить этот массив о его длине, а затем пройтись по нему, выбирая элементы массива. Эта способность легкого прохода по массиву вне методов и в методах является значительным улучшением по сравнению с поведением C и C++.
Анонимные внутренние классы
Здесь показано как анонимный внутренний класс позволяет создать быстрые и грязные классы для решения проблемы. Так как все в Java вертится вокруг классов, это может быть полезной техникой написания программ. Одна из выгод в том, что программа содержит код, который решает определенную проблему, изолированную в одном месте. С другой стороны, это не всегда легче для чтения, так что вы должны использовать это с умом.
Поиск и создание директориев
В fileData( ) вы можете видеть различные способы исследования файла для отображения информации о файле или о пути директории.
Если вы поэкспериментируете с приведенной выше программой, вы обнаружите, что вы можете создать путь директорий любой сложности, потому что mkdirs( ) будет делать всю работу за вас.
Ввод и вывод
Библиотеки ввода/вывода часто используют абстракцию потока, который представляется любым источником данных или представляется как объект, способный производить или принимать кусочки данных. Поток прячет детали того, что случается с данными внутри реального устройства ввода/вывода.
Библиотечные классы Java для ввода/вывода делятся на классы ввода и вывода, как вы можете увидеть, взглянув на иерархию Java классов в онлайн документации с помощью вашего Web броузера. При наследовании, все, что наследуется от классов InputStream или Reader, имеет основной метод, называемый read( ) для чтения единичного байта или массива байт. Точно так же, все, что наследуется от классов OutputStream или Writer, имеет основной метод, называемый write( ) для записи единичного байта или массива байт. Однако чаще всего вы не можете использовать эти методы; они существуют для того, чтобы другие классы могли использовать их — эти другие классы обеспечивают более полезные интерфейсы. Таким образом, вы редко будете создавать ваш объект потока, используя единственный класс, вместо этого вы будите располагать множеством объектом для обеспечения желаемой функциональности. Факт в том что вы создаете более, чем один объект для создания единственного результирующего потока, это главная причина, по которой потоки Java являются запутанными.
Типы InputStream
Работа InputStream состоит в представлении классов, которые производят ввод от различных источников. Источниками могут быть:
Таблица 11-1. Типы InputStream
Типы OutputStream
Эта категория включает классы, которые решают, куда будет производиться вывод: в массив байт (но не String ; возможно, вы можете создать его, используя массив байт), в файл, или в “трубу”.
Кроме того, FilterOutputStream обеспечивает базовый класс для «декорирования» классов, которые присоединяют атрибуты или полезные интерфейсы для выходного потока. Это будет обсуждаться позже.
Таблица 11-2. Типы OutputStream
Добавление атрибутов и полезных интерфейсов
Декорирование часто используется, когда простое использование подклассов в результате приводит к большому числу подклассов, способных удовлетворить каждую возможную необходимую комбинацию, что становится непрактично. Библиотека ввода/вывода Java требует много различных комбинаций особенностей, которые являются причиной использования шаблона декоратора. Однако для шаблона декоратора есть препятствие. Декораторы дают вам много больше гибкости, когда вы пишите программу (так как вы можете легко смешивать и сравнивать атрибуты), но они привносят сложность в ваш код. Причина того, что библиотека Java неудобна в использовании, состоит в том, что вы должны создавать много классов — “центральные” типы ввода/вывода, плюс все декораторы — для того, чтобы создать единственный объект ввода/вывода, который вам нужен.
Чтение из InputStream с помощью FilterInputStream
Классы FilterInputStream совершают две значительные вещи. DataInputStream позволяет вам читать различные типы примитивных данных, наряду с объектами типа String. (Все методы начинаются со слова “read”, например: readByte( ), readFloat( ), и т.п.) Таким образом, наряду со своим компаньоном DataOutputStream, это позволяет вам перемещать примитивные данные из одного места в другое через поток. Эти “места” определяются классами в таблице 11-1.
Оставшиеся классы изменяют способ внутреннего поведения InputStream: будет ли он буферизированный или нет, будет ли он хранить историю прочитанных строк (позволяя вам спрашивать номер строки или множества номеров строк), и сможете ли вы поместить назад единичный символ. Последние два класса выглядят так, как будто они предназначены для поддержки работы компилятора (то есть, они были добавлены для поддержки конструкций Java компилятора), так что вы, вероятно, не захотите использовать их в обычном программировании.
Вероятно, вам необходимо будет буферизировать ваш ввод почти каждый раз, в зависимости от устройства ввода/вывода, к которому вы подсоединяетесь, так что имеет больше смысла для библиотеки ввода/вывода сделать особый случай (или простой вызов метода) для не буферизированного ввода, в отличие от буферизированного ввода.
Таблица 11-3. Типы FilterInputStream
Запись в OutputStream с помощью FilterOutputStream
Изначальное предназначение PrintStream было в печати всех примитивных типов данных и объектов String в удобочитаемом формате. Он отличается от DataOutputStream, чья цель состоит в помещении элементов данных в поток таким способом, чтобы DataInputStream мог без труда реконструировать их.
Двумя важнейшими методами PrintStream являются print( ) и println( ), которые перегружены для печати всех различных типов. Различия между print( ) и println( ) в том, что последний метод добавляет символ новой строки, когда завершен вывод.
PrintStream может быть проблематичным, поскольку он ловит все IOException (вы должны явно проверять статус ошибки с помощью checkError( ), который возвращает true, если возникла ошибка). Так же PrintStream не интернацианализован полностью и не обрабатывает переводы строки платформонезависимым способом (эти проблемы решаются с помощью PrintWriter).
BufferedOutputStream является модификатором и говорит потоку, что нужно использовать буферизацию, так что вы не получите физической записи при каждой записи в поток. Вы, вероятно, всегда захотите использовать это с файлами, и, возможно, при консольном вводе/выводе.
Таблица 11-4. Типы FilterOutputStream
Читающие и пишущие
В Java 1.1 сделаны некоторые значительные модификации в фундаментальной библиотеке потоков ввода/вывода (однако Java 2 не внесла фундаментальных модификаций). Когда вы видите классы Reader и Writer, вы сначала можете подумать (как и я), что они предназначены для замены классов InputStream и OutputStream. Но не в этом случае. Хотя некоторые аспекты начальной библиотеки потоков устарели и были заменены (если вы используете их, вы должны получать предупреждение компилятора), классы InputStream и OutputStream все еще обеспечивают ценную функциональность в форме байт-ориентированных систем ввода/вывода, в то время как классы Reader и Writer обеспечивают Unicode-совместимый, символьно ориентированный ввод/вывод. Кроме того:
Как практикуется в этой книге, я попробую выполнить обзор классов, но вы должны принять во внимание, что вы будете использовать онлайн документацию для определения всех деталей, таких как исчерпывающий список методов.
Источники и приемники данных
Почти все оригинальные классы потоков ввода/вывода имеют соответствующие классы Reader и Writer для обеспечения родных манипуляций в Unicode. Однако есть некоторые места, где байт-ориентированные InputStream и OutputStream являются корректным решением; на практике библиотеки из java.util.zip скорее байт-ориентированные, чем символьно-ориентированные. Так что наиболее разумным подходом будет попытка использования классов Reader и Writer там, где э то возможно, и вы обнаружите ситуации, когда будете вынуждены использовать байт-ориентированные библиотеки, потому что ваш код не будет компилироваться.
Здесь приведена таблица, которая показывает соответствие между источниками и приемниками информации (то есть, куда данные приходят на физическом уровне или куда они уходят) в двух иерархиях.
Источники и приемники: класс Java 1.0 | Соответствующий класс Java 1.1 |
---|---|
InputStream | Reader конвертер: InputStreamReader |
OutputStream | Writer конвертер: OutputStreamWriter |
FileInputStream | FileReader |
FileOutputStream | FileWriter |
StringBufferInputStream | StringReader |
(соответствующего класса нет) | StringWriter |
ByteArrayInputStream | CharArrayReader |
ByteArrayOutputStream | CharArrayWriter |
PipedInputStream | PipedReader |
PipedOutputStream | PipedWriter |
В общем случае вы обнаружите, что интерфейсы для этих двух различных иерархий сходны, если не идентичны.
Модификация поведения потока
Потоки InputStream и OutputStream адаптируются под определенные требования с использованием “декорирующих” подклассов FilterInputStream и FilterOutputStream. Классы иерархии Reader и Writer продолжают использовать эту идею — но не точно.
В приведенной таблице соответствие произведено с еще большим приближением, чем в предыдущей таблице. Различия происходят из-за организации классов: в то время как BufferedOutputStream является подклассом FilterOutputStream, BufferedWriter не является подклассом FilterWriter (который, не смотря на то, что он является абстрактным, не имеет подклассов и, таким образом, появляется помещенным в любой объект, а здесь упомянуть просто для того, чтобы вы не удивились, увидев его). Однако интерфейсы классов достаточно близки при сравнении.
Есть одно направление, которое достаточно понятно: Когда вы хотите использовать readLine( ), вы не должны более использовать DataInputStream (при этом вы встретитесь с сообщении об использовании устаревших методов во время компиляции), а вместо этого использовать BufferedReader. Тем не менее, DataInputStream все еще остается “привилегированным” членом библиотеки ввода/вывода.
Чтобы сделать переход к использованию PrintWriter более легким, он имеет конструктор, который принимает любой объект типа OutputStream, наряду с объектами Writer. Однако PrintWriter более не поддерживает форматирование, которое поддерживал PrintStream; интерфейс, фактически, остался тем же.
Конструктор PrintWriter также имеет необязательную опцию для выполнения автоматической выгрузки буферов, которая случается после каждого вызова println( ), если установлен флаг в конструкторе.
Неизмененные классы
Некоторые классы остались неизменными при переходе от Java 1.0 к Java 1.1:
Классы Java 1.0 не имеющие соответствующих классов в Java 1.1 |
---|
DataOutputStream |
File |
RandomAccessFile |
SequenceInputStream |
Сам по себе: RandomAccessFile
RandomAccessFile используется для файлов, содержащих записи известного размера, так что вы можете переместиться от одной записи к другой, используя seek( ), затем прочесть или изменить запись. Записи могут и не быть одинакового размера; вы просто способны определить их размер и их положение в файле.
Сначала немного трудно поверить, что RandomAccessFile не является частью иерархии InputStream или OutputStream. Однако он не имеет ассоциаций с этими иерархиями, за исключением того, что он реализует интерфейсы DataInput и DataOutput (которые так же реализуются DataInputStream и DataOutputStream). Он даже не использует любую функциональность существующих классов InputStream или OutputStream — это полностью отдельный класс, написанный для поиска, имеющий все свои собственные (в большинстве своем родные) методы. Объяснением этого может быть то, что RandomAccessFile имеет во многом отличающееся поведение по сравнению с остальными типами ввода/вывода, так как вы можете перемещаться вперед и назад в пределах файла. В любом случае, он стоит отдельно, как прямой потомок от Object.
По существу, RandomAccessFile работает как DataInputStream совмещенный с DataOutputStream, благодаря использованию методов getFilePointer( ) для нахождения местоположения в файле, seek( ) для перемещения в новую точку в файле и length( ) для определения максимального размера файла. Кроме того, конструктор требует второй аргумент (что идентично fopen( ) в C), указывающий будите ли вы производить только чтение в произвольном порядке (“r”) или чтение и запись (“rw”). Нет поддержки для файлов только для чтения, что может сказать о том, что RandomAccessFile мог бы хорошо работать, если он наследовался бы от DataInputStream.
Типичное использование потоков ввода/вывода
Хотя вы можете комбинировать классы потоков ввода/вывода многими различными способами, вы, вероятно, будете использовать несколько комбинаций. Следующий пример может быть использован как отправная точка; он показывает создание и использование типичной конфигурации ввода/вывода. Обратите внимание, что каждая конфигурация начинается с порядкового номера и заголовка, который оглавляет соответствующее объяснение в следующем за ним тексте.
Здесь приведено описание для нумерованных разделов программы:
Потоки ввода
Части с 1 по 4 демонстрируют создание и использование потоков ввода. Часть 4 также показывает простое использование потока вывода.
1. Буферизированный ввод из файла
Для открытия файла для ввода символов вы используете FileInputReader с объектом String или File в качестве имени файла. Для быстрой работы вы можете захотеть, чтобы файл был буферизированный, поэ тому вы передаете результирующую ссылку в конструктор BufferedReader. BufferedReader также обеспечивает метод readLine( ), так что это ваш конечный объект и интерфейс, из которого вы читаете. Когда вы достигаете конца файла, readLine( ) возвращает null, что используется для окончания цикла while.
String s2 использует для аккумулирования всего содержимого файла (включая символы новой строки, которые должны добавляться, поскольку readLine( ) отбрасывает их). s2 далее используется в следующих частях этой программы. В конце вызывается close( ) для закрытия файла. Технически, close( ) будет вызвано при запуске finalize( ), а это произойдет (не зависимо от того произойдет или нет сборка мусора) при выходе из программы. Однако это было реализовано неустойчиво, поэтому безопасным подходом является явный вызов close( ) для файлов.
2. Ввод из памяти
3. Форматированный ввод из памяти
Для чтения “форматированных” данных вы используете DataInputStream, который является байт-ориентированным классом ввода/вывода (а не символьно-ориентированным). Таким образом, вы должны использовать все классы InputStream, а не классы Reader. Конечно, вы можете читать все, что угодно (также как и файл) байтами, используя классы InputStream, но здесь используется String. Для преобразования String в массив байт, который является подходящим для ByteArrayInputStream, String имеет метод getBytes( ), чтобы сделать эту работу. В этой точке вы имеете соответствующий InputStream для управления DataInputStream.
Вы также можете определить конец ввода в таком случае, как здесь, при поимке исключения. Однако использование исключений для управления выполнением программы, рассматривается как злоупотребление этой особенностью.
4. Вывод в файл
Этот пример также показывает, как писать данные в файл. Сначала создается FileWriter для соединения с файлом. Фактически, вы всегда будете буферизировать вывод, обернув его с помощью BufferedWriter (попробуйте удалить эту обертку, чтобы посмотреть влияние на производительность — буферизация позволяет значительно увеличить производительность операций ввода/вывода). Затем, для форматирование объект включен в PrintWriter. Файл данных, созданный этим способом, читаем, как обычный текстовый файл.
Когда строки записываются в файл, добавляются номера строк. Обратите внимание, что LineNumberInputStream не используется, потому что он слабый и вам не нужен. Как показано здесь, достаточно просто хранить свою историю номеров строк.
Выходные потоки
5. Сохранение и возврат
PrintWriter форматирует данные так, чтобы их читали люди. Однако для вывода данных в виде, чтобы они могли быть возвращены в другой поток, используйте DataOutputStream для записи данных, а DataInputStream для обратного получения данных. Конечно, эти потоки могут быть всем, что угодно, но здесь используется файл, буферизируемый и для чтения, и для записи. DataOutputStream и DataInputStream являются байт-ориентированными и поэтому требуют потоков InputStream и OutputStream.
Если вы используете DataOutputStream для записи данных, то Java гарантирует, что вы можете безошибочно повторно задействовать данные, используя DataInputStream — не зависимо от различий платформ для записи и чтения данных. Это невероятно ценно, как могут подтвердить те, кто потратил время, заботясь о платформозависимых путях движения данными. Эти проблемы снимаются, если вы имеете Java на обеих платформах. [58]
Обратите внимание, что строки символов записываются с использованием как writeChars( ), так и writeBytes( ). Когда вы запустите программу, вы обнаружите, что выводит 16-битные символы Unicode. Когда вы читаете строки, используя readLine( ), вы увидите, что есть пространство между символами, потому что каждый дополнительный байт вставляется из-за Unicode. Так как нет дополнительного метода “readChars” для DataInputStream, вы вынуждены вытягивать символы по одному с помощью readChar( ). Так что для ASCII легче написать символы байтами, за которым следует новая строка, а затем использовать readLine( ) для чтения байтов, как обычной ASCII cтроки.
writeDouble( ) сохраняет числа типа double в потоке, а дополнительный метод readDouble( ) получает их обратно (есть аналогичные методы для чтения и записи остальных типов). Но для корректной работы с любым читающим методом вы должны знать точное положение элемента данных в потоке, чтобы было одинаково возможно читать хранимое double, как простую последовательность байт, или как char, и т.п. Таким образом, вы должны либо иметь фиксированный формат для данных в файле, или в файле должна хранится дополнительная информация, которую вы обработаете для определения местоположения данных.
6. Чтение и запись файлов произвольного доступа
Как было замечено ранее, RandomAccessFile почти полностью изолирован от оставшейся иерархии ввода/вывода, и подтвержден тот факт, что он реализует интерфейсы DataInput и DataOutput. Поэтому вы не можете комбинировать его с любыми другими аспектами подклассов InputStream и OutputStream. Даже при том, что имело бы смысл трактовать ByteArrayInputStream, как элемент произвольного доступа, вы можете использовать RandomAccessFile только для открытия файла. Вы должны иметь в виду, что RandomAccessFile буферизирован должным образом, так что вам не нужно заботится об этом.
Одну из настроек вы имеете во втором конструкторе аргумента: вы можете открыть RandomAccessFile для чтения (“r”) или для чтения и записи (“rw”).
Использование RandomAccessFile аналогично использования комбинации DataInputStream и DataOutputStream (потому что он реализует эквивалентные интерфейсы). Кроме того, вы можете видеть, что seek( ) используется для перемещения в файле и изменения одного значения на другое.
Ошибка?
Если вы взглянете на раздел 5, вы увидите, что данные записываются перед текстом. Дело в том, что эта проблема была представлена в Java 1.1 (и сохранилась в Java 2), я был уверен, что это ошибка. Когда я сообщил об этом людям, занимающимся ошибками в JavaSoft, они сказали мне, что это, Проблема показана в следующем коде:
Кажется что все, что вы пишите после вызова writeBytes( ) не возвращаемо. Ответ, очевидно, тот же, что и в случае старой шутки водителя: “Доктор, мне больно, когда я делаю это!” “Так не делайте этого!”
Потоки в виде трубопровода
Стандартный ввод/вывод
Термин стандартный ввод/вывод относится к концепции Unix (которая в некоторой форме была воспроизведена в Windows и многих других операционных системах) единого потока информации, который используется программой. Весь ввод программы может вестись через стандартный ввод, весь вывод может идти в стандартный вывод, а все сообщения об ошибках могут посылаться в стандартный поток ошибок. Значение стандартного ввода/вывода в том, что программы легко могут представлять цепочку вместе, и стандартный вывод одной программы может стать стандартным вводом для другой. Это достаточно мощный инструмент.
Чтение из стандартного ввода
Замена System.out на PrintWriter
Перенаправление стандартного ввода/вывода
Класс Java System позволяет вам перенаправлять стандартный ввод, вывод и поток вывода ошибок, используя простой вызов статического метода:
setIn(InputStream)
setOut(PrintStream)
setErr(PrintStream)
Перенаправление вывода особенно полезно, если вы неожиданно начнете создание большого объема для вывода на экран, а он будет скроллироваться гораздо быстрее, чем выбудете успевать читать. [59] Перенаправление ввода важно для программ командной строки, в которых вы захотите протестировать определенные последовательности пользовательского ввода несколько раз. Вот пример, показывающий использование этих методов:
Эта программа соединяет стандартный ввод с файлом и перенаправляет стандартный вывод и стандартные ошибки в другой файл.
Компрессия
Библиотека ввода/вывода Java содержит классы, поддерживающие чтение и запись потоков в компрессированном формате. Они являются оберткой для существующих классов ввода/вывода для обеспечения возможности компрессирования.
Эти классы не наследуются от классов Reader и Writer, а вместо этого они являются частью иерархии InputStream и OutputStream. Это происходит потому, что библиотека компрессии работает с байтами, а не с символами. Однако вы можете иногда встретить необходимость смешивания двух типов потоков. (Помните, что вы можете использовать InputStreamReader и OutputStreamWriter для обеспечения простой конвертации одного типа в другой. )
Хотя существует много алгоритмов компрессии, Zip и GZIP, вероятно, наиболее часто используемые. Поэтому вы можете легко манипулировать вашими компрессированными данными с помощью многих инструментов, существующих для чтения и записи этих форматов.
Простая компрессия с помощью GZIP
Интерфейс GZIP прост, и поэтому он является более подходящим, когда вы имеете единственный поток данных, которые хотите компрессировать (в отличие от случая, когда вы имеете кусочки разнородных данных). Здесь приведен пример компрессии единичного файла:
Многофайловое хранение с использованием Zip
Библиотека, поддерживающая Zip формат, более обширная. С ее помощью вы можете легко хранить множественные файлы, есть даже отдельные файлы, которые делают легким процесс чтения Zip файла. Библиотека использует стандартный Zip формат, так что он может работать совместно со всеми инструментами, которые доступны в Internet. Следующий пример имеет ту же форму, что и предыдущий, но он обрабатывает столько аргументов командной строки, сколько вы захотите. Кроме того, он показывает использование классов Checksum для подсчета и проверки контрольной суммы для файла. Есть два типа Checksum : Adler32 (который быстрее) и CRC32 (который медленнее, но немного более аккуратный).
Для каждого файла, добавляемого в архив, вы должны вызвать putNextEntry( ) и передать ему объект ZipEntry. Объект ZipEntry содержит обширный интерфейс, который позволит вам получить и установить все данные, доступные для этого конкретного включения в ваш Zip файл: имя, компрессированный и не компрессированный размеры, дата, CRC контрольная сумма, дополнительное поле данных, комментарий, метод компрессии и есть ли включаемые директории. Однако, хотя формат Zip имеет возможность установки пароля, это не поддерживается в Zip библиотеке Java. И хотя CheckedInputStream и CheckedOutputStream поддерживают обе контрольные суммы Adler32 и CRC32, класс ZipEntry поддерживает только интерфейс для CRC. Это является ограничением лежащего в основе Zip формата, и это может ограничить вас в использовании быстрого Adler32.
Для чтения контрольной суммы вы должны как-то получить доступ к ассоциированному объекту Checksum. Здесь получается ссылка на объекты CheckedOutputStream и CheckedInputStream, но вы также могли просто владеть ссылкой на объект Checksum.
Трудным методом для потоков Zip является setComment( ). Как показано выше, вы можете установить комментарий, когда вы записываете файл, но нет способа получить коментарий в ZipInputStream. Комментарии появились для полной поддержки базиса включение-за-включением только через ZipEntry.
Конечно, вы не ограничены в файлах, когда используете библиотеки GZIP или Zip — вы можете компрессировать все, что угодно, включая данные для посылки через сетевое соединение.
Java архивы (JAR’ы)
Формат Zip также используется в файле, формата JAR (Java ARchive), который является способом сбора группы файлов в один компрессированный файл, так же как и Zip. Однако, как и все остальное в Java, JAR файлы являются кроссплатформенными, так что вам не нужно беспокоится о возможностях платформы. Вы также можете включить звуковой и графический файл наряду с файлами классов.
JAR файлы обычно полезны, когда вы имеете дело с Internet. До появления JAR файлов ваш Web броузер делал повторяющиеся запросы к Web серверу для загрузки всех файлов, из которых состоит апплет. Кроме того, каждый из этих файлов был не компрессирован. При сборе всех этих файлов для определенного апплета в единый JAR файл необходим только один запрос к серверу, а передача пройдет быстрее из-за компрессии. А каждое включение в JAR файл может иметь цифровую подпись для безопасности (обратитесь за деталями к документации по Java).
JAR файл состоит из единого файла, содержащего набор файлов, упакованных с помощью Zip, наряду с “ манифестом”, который описывает их. (Вы можете создать свой собственный файл манифеста; в противном случае программа jar сделает это за вас.) Вы можете найти больше информации о файлах манифеста JAR в HTML документации для JDK.