Символьные потоки CharArray и String 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Символьные потоки CharArray и String



 

Символьные потоки семейства CharArray (CharArray Reader и CharArray Writer) аналогичны по назначению потокам ByteArray – они позволяют в качестве источника или получателя данных использовать массивы типа char, размещённые в памяти. В составе класса CharArrayWriter предусмотрены средства динамического наращивания объёма массива типа char, получающего выводимые данные. Объект класса StringReader позволяет считывать символы из строки String. Объект класса StringWriter позволяет записывать символы в буфер, который может интерпретироваться как объект типа String или StringBuffer.

 

Потоки Print

 

Классы семейства Print – PrintStream и PrintWriter – содержат объявление ряда методов, которые упрощают задачу вывода (записи) в поток значений простых типов и объектов в удобочитаемом текстовом формате. В потоковых классах Print реализованы перегруженные версии методов print() и println() для вывода следующих значений типов – char, char[], int, long, float, double, Object, String, boolean. Эти методы гораздо удобнее для применения, нежели обычные методы потокового вывода (записи) write(). Метод println() добавляет в конец порции выводимых данных, переданной в виде параметра, признак завершения строки (без параметров просто завершает текущую строку).

Каждый из потоков Print действует как поток Filter, и поэтому в процессе вывода данные могут быть подвержены дополнительной фильтрации. Класс PrintStream работает с байтовыми потоками, а PrintWriter – с символьными. Поскольку чаще возникает потребность в записи символов, в обычных ситуациях следует пользоваться средствами класса PrintWriter.

Одна из важных характеристик поведения потоков Print связана с тем, что ни один из реализованных в них методов вывода (записи) не выбрасывает исключения типа IOException. Если при передаче данных «внутреннему» потоку возникает ошибка, методы завершают выполнение нормальным образом. Проверить наличие ошибки можно с помощью вызова метода checkError(), возвращающего результат типа boolean.

 

Класс StreamTokenizer

 

Задачи лексического анализа потока данных относятся к числу традиционных и в составе пакета java.io представлен класс StreamTokenizer, позволяющий решать некоторые из них. Поток разбивается на лексемы с помощью объекта StreamTokenizer, конструктор которого принимает в качестве параметра объект типа Reader, выполняющий функцию источника данных; объект StreamTokenizer действует в соответствии с заданными параметрами сканирования данных. На каждой итерации цикла сканирования вызывается метод nextToken(), который возвращает очередную считанную из потока лексему и информацию о её типе, присваивая эти данные полям объекта StreamTokenizer.

Класс StreamTokenizer ориентирован преимущественно на анализ текстов, представляющих код, написанный на каком-либо языке программирования; класс нельзя отнести к числу инструментов лексического анализа общего назначения.

Когда метод nextToken распознаёт лексему, он возвращает её тип в виде значения и присваивает последнее полю ttype.

Существует четыре типа лексем, воспринимаемых методом nextToken():

TT_ WORD; обнаружено слово; оно сохраняется в поле sval типа String

TT_ NUMBER; обнаружено число; оно сохраняется в поле nval типа double; распознаются только десятичные числа с плавающей запятой (с десятичной точкой или без таковой) в нормальной нотации (анализатор не распознает ни 3.4е79 как число с плавающей запятой, ни 0xffff как шестнадцатеричное число)

TT_ EOL; обнаружен признак завершения строки

TT_ EOF; достигнут конец файла

Подразумевается, что текст, подлежащий анализу, состоит из байтов, значение которых относятся к диапазону от \u0000 до \u00FF, - корректность распознавания символов Unicode, не принадлежащих указанному интервалу, не гарантируется. Поток ввода включает специальные и обычные символы. К категории специальных относятся те символы, которые анализатор трактует специальным образом, а именно: символы пробела, символы, обозначающие числа и слова, и т.д. Любой другой символ воспринимается как обычный. Когда очередным символом потока является обычный символ, в качестве его типа возвращается значение этого символа.

Пример 3

static double sumStream(Reader in) throws IOException {

StreamTokenizer nums = new StreamTokenizer(in);

double result = 0.0;

while (nums.nextToken()!= StreamTokenizer.TT_EOF) {

     if (nums.ttype == StreamTokenizer.TT_NUMBER)

          result += nums.nval;

}

return result;

}

 

Байтовые потоки Data

 

В интерфейсах DataInput и DataOutput определены методы потокового ввода-вывода данных простых типов, а классы DataInputStream и DataOutputStream обеспечивают реализацию интерфейсов, предлагаемую по умолчанию. Интерфейсы, предусматривающие потоковый ввод и вывод бинарных данных, обладают почти одинаковой структурой.

Ниже перечислены методы семейств read и write, обеспечивающих ввод и вывод данных каждого из простых типов:

readBoolean (writeBoolean), readChar (writeChar), readByte (writeByte), readShort (writeShort), readInt (writeInt), readLong (writeLong), readFloat (writeFloat), readDouble (writeDouble), readUTF (writeUTF)

Методы интерфейса DataInput обычно реагируют на событие достижения конца потока, выбрасывая исключение типа EOFException, производного от IOException.

 

Для каждого интерфейса Data существует определённый поток Data. Кроме того, имеется класс RandomAccessFile, который реализует одновременно оба интерфейса Data – ввода и вывода. Каждый класс Data является расширением соответствующего класса Filter, так что потоки Data могут использоваться в целях фильтрации данных других потоков. В составе каждого класса Data есть конструкторы, в качестве параметра принимающие ссылки на другой подходящий поток ввода или вывода.

Примеры реализации соответствующих методов приведены в примере 4.

 

Пример 4

public static void writeData(double[] data, String file) throws IOException {
     OutputStream fout = new FileOutputStream(file);

         DataOutputStream out = new DataOutputStream(fout);

         out.writeInt(data.length);

        for (int i =0; i < data.length; i++)

             out.writeDouble(data[i]);

       out.close();

}

 

public static double[] readData(String file) throws IOException {
        InputStream fin = new FileInputStream(file);

          DataInputStream in = new DataInputStream(fin);

             double[] data = new double[in.readInt()];

            for (int i =0; i < data.length; i++)

                data[i] = in.readDouble();

            in.close();

            return data;

}

 

Класс File

 

Класс File реализует ряд полезных средств для работы с файлами и директориями: создание, проверка атрибутов, удаление, переименование. В составе класса File также объявлены методы, которые позволяют создавать временные файлы, используемые, например, для хранения промежуточных результатов и удаляемые при завершении работы программы.

 

Потоки File

 

Потоковые классы семейства File – FileInputStream, FileOutputStream, FileReader и FileWriter – позволяют трактовать файл как поток, предназначенный для ввода(чтения) или вывода(записи) данных. В составе каждого из типов предусмотрены три конструктора, принимающие в качестве параметра одно из следующих значений:

• строку String, задающую имя файла

• объект класса File, указывающий на файл

• объект FileDescriptor

Объект FileDescriptor служит для представления сущности, описывающей открытый файл и определяемой особенностями применяемой операционной системы. Если при использовании байтового или символьного потоков ввода (чтения), обнаруживается, что файл не существует, выбрасывается исключение типа FileNotFoundException. При доступе к файлу во всех случаях проверяется наличие соответствующих полномочий: если необходимые права на обращение к файлу отсутствуют, генерируется исключение типа SecurityException. Два первых конструктора при построении байтового или символьного потоков вывода(записи) предусматривают создание файла, если такого не существует, при наличии файла его содержимое усекается.

 

 

Сериализация объектов. Подготовка классов к сериализации. Порядок сериализации и десериализации. Настройка механизма сериализации. Контроль версий объектов.

 

Сериализация объектов

 

Одной из существенных возможностей многих реальных приложений является их способность преобразовывать объекты в байтовые потоки, которые могут передаваться в пределах сети - например, с целью использования в рамках технологии удалённого вызова метода, - сохраняться на диске в виде файлов, а затем при необходимости восстанавливаться в форме «живых» объектов. Процесс преобразования содержимого объекта в поток байтов принято называть сериализацией объекта, а обратное преобразование – восстановление объекта из данных потока – десериализацией.

Потоки Object – ObjectOutputStream и ObjectInputStream - позволяют осуществлять сериализацию и десериализацию объектов. ObjectInputStream и ObjectOutputStream, помимо данных стандартных классов (простых типов, строк и их массивов) позволяют вводить и выводить графы объектов.

Под термином граф объекта имеется в виду, что когда содержимое объекта выводится в поток ObjectOutputStream средствами методов writeObject(), в потоки сохраняются наборы байтов, представляющие и текущий объект, и все другие объекты, на который тот ссылается. Поскольку данные об объекте, подвергшимся сериализации, представляются в форме байтов, в семействе потоков Object отсутствуют символьные разновидности Reader и Writer. Результатом десериализации последовательности байтов, представляющих ранее сериализованный объект, из потока ObjectInputStream с помощью методов readObject служит граф объекта, равнозначный исходному.

Пример 5

// Сериализация

LinkedList ls = new LinkedList();

FileOutputStream fileOut = new FileOutputStream("list");

ObjectOutputStream out = new ObjectOutputStream(fileOut);

out.writeObject(ls);

 

// Десериализация

FileInputStream fileIn = new FileInputStream("list");

ObjectInputStream in = new ObjectInputStream(fileIn);

LinkedList ls = (LinkedList) in.readObject();

 

Подготовка классов к сериализации

 

Необходимым условием возможности осуществления сериализации объектов класса средствами потока ObjectOutputStream является реализация классом интерфейса-маркера Serializable. Поддержка классом интерфейса Serializable свидетельствует о том, что объекты класса готовы к сериализации.

По умолчанию процесс сериализации заключается в сериализации каждого поля объекта, которое не обозначено как transient или static. Данные простых типов и строки сохраняются с помощью того же механизма, какой поддерживается потоками DataOutputStream, а сериализация объектов выполняется средствами метода writeObject().

Схема сериализации, предусмотренная по умолчанию, предполагает, что все поля-объекты, подлежащие сериализации, должны указывать на типы, в свою очередь поддерживающие возможность сериализации. Кроме того, требуется, чтобы класс, базовый по отношению к рассматриваемому, либо обладал конструктором без параметров (чтобы он мог быть вызван в процессе десериализации), либо сам в свою очередь обеспечивал реализацию интерфейса Serializable. В большинстве ситуаций для обеспечения возможности сериализации объектов класса вполне достаточно тех мер, которые предусмотрены схемой сериализации, предлагаемой по умолчанию, и проблема исчерпывается простым упоминанием интерфейса Serializable в объявлении класса.

Схема десериализации, предлагаемая по умолчанию, предусматривает считывание из потока байтовых данных, сохранённых в процессе сериализации. Статические поля класса остаются в неприкосновенности – в ходе загрузки класса будут выполнены все обычные процедуры инициализации, и статические поля получат требуемые исходные значения. Каждому полю transient в восстановленном объекте присваивается значение по умолчанию, соответствующее типу этого поля.

Иногда встречаются классы, которые сами по себе допускают возможность сериализации, но их отдельные элементы – нет. Любая попытка осуществления сериализации объекта, не поддерживающего эту возможность, приводит к выбрасыванию исключения типа NotSerializableException.

 



Поделиться:


Последнее изменение этой страницы: 2021-05-11; просмотров: 86; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.129.67.26 (0.021 с.)