Назад
Вперед
7.12. Создание потоков в оперативной памяти
На примере аплета в примере демонстрируются
методы организации объектно-ориентированного
вывода в потоки, созданные в оперативной памяти
как объекты классов ByteArrayOutputStream и ввода из
потоков, созданных на базе класса ByteArrayInputStream.
Вывод и ввод объектов класса Vector выполняется с
применением классов ObjectOutputStream и ObjectInputStream,
соответственно.
Исходный текст примера
Архив проекта для Java WorkShop 2.0
Демонстрация
(ваш браузер должен уметь работать с аплетами
Java JDK 1.1)
Немного теории
При создании приложений и аплетов Java вы также
можете работать с объектами оперативной памяти,
как с потоками. Это имеет особенное значение для
аплетов, которым запрещено обращаться к файлам,
расположенным на локальном диске компьютера.
В библиотеке классов Java есть три класса,
специально предназначенных для создания потоков
в оперативной памяти. Это классы ByteArrayOutputStream,
ByteArrayInputStream и StringBufferInputStream.
Класс ByteArrayOutputStream
Класс ByteArrayOutputStream создан на базе класса OutputStream.
В нем имеется два конструктора, прототипы
которых представлены ниже:
public ByteArrayOutputStream();
public ByteArrayOutputStream(int size);
Первый из этих конструкторов создает выходной
поток в оперативной памяти с начальным размером
буфера, равным 32 байта. Второй позволяет указать
необходимый размер буфера.
В классе ByteArrayOutputStream определено несколько
методов:
public void reset();
public int size();
public byte[] toByteArray();
public void writeTo(OutputStream out);
Метод reset сбрасывает счетчик байт, записанных в
выходной поток. С помощью метода size можно
определить количество байт данных, записанных в
поток.
Метод toByteArray позволяет скопировать данные,
записанные в поток, в массив байт. Этот метод
возвращает ссылку на созданный для этой цели
массива.
С помощью метода writeTo вы можете скопировать
содержимое данного потока в другой выходной
поток, ссылка на который передается методу через
параметр.
Для выполнения форматированного вывода в
поток, вы должны создать поток на базе таких
классов как DataOutputStream или ObjectOutputStream, передав
соответствующему конструктору ссылку на поток
класса ByteArrayOutputStream.
Класс ByteArrayInputStream
С помощью класса ByteArrayInputStream вы можете создать
входной поток на базе массива байт,
расположенного в оперативной памяти. В этом
классе определено два конструктора:
public ByteArrayInputStream(byte buf[]);
public ByteArrayInputStream(
byte buf[], int offset, int length);
Первый конструктор получает через
единственный параметр ссылку на массив, который
будет использован для создания входного потока.
Второй позволяет дополнительно указать смещение
offset и размер области памяти length, которая будет
использована для создания потока.
Вот несколько методов, определенных в классе
ByteArrayInputStream:
public int available();
public int read();
public int read(byte b[],int off, int len);
public void reset();
public long skip(long n);
С помощью метода available можно определить,
сколько байт имеется во входном потоке для
чтения.
Обычно класс ByteArrayInputStream используется вместе с
классом DataInputStream или ObjectInputStream, что позволяет
организовать форматный ввод данных.
Класс StringBufferInputStream
Класс StringBufferInputStream предназначен для создания
входного потока на базе текстовой строки класса
String. Ссылка на эту строку передается
конструктору класса StringBufferInputStream через параметр:
public StringBufferInputStream(String s);
В классе StringBufferInputStream определены те же методы,
что и в только что рассмотренном классе
ByteArrayInputStream.
Описание примера
Наш аплет создан на базе автономного
приложения, рассмотренного в разделе "7.4. Сохранение объекта Java в
файле". Это приложение позволяет сохранять
нарисованные в его окне прямые линии в файле. Так
как аплет не может работать с локальными файлами
(в JDK версий 1.0 и 1.1), мы выполняем сохранение в
потоке, размещенном в оперативной памяти.
В окне нашего аплета имеется три кнопки и
панель для рисования линий (рис. 1).
Рис. 1. Окно аплета с нарисованными в нем линиями
Нарисовав что-нибудь внутри желтой панели, вы
можете сохранить рисунок, нажав кнопку Save. Если
затем, не покидая страницы HTML с аплетом, стереть
рисунок кнопкой Clear или двойным щелчком мыши в
окне аплета, его нетрудно будет восстановить,
нажав кнопку Restore.
Рассмотрим исходный текст аплета.
Главный класс
Главный класс аплета создан на базе класса Applet
и реализует интерфейс ActionListener:
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
public class MemoryStream extends Applet
implements ActionListener
{
. . .
}
В главном классе определены поля для хранения
ссылок на кнопки и на панель рисования класса
DrawPanel, определенного в нашем приложении:
Button btnClear;
Button btnSave;
Button btnRestore;
DrawPanel dp;
Метод init главного класса
При инициализации аплета мы создаем три кнопки
и добавляем их в окно аплета:
btnClear = new Button("Clear");
btnSave = new Button("Save");
btnRestore = new Button("Restore");
add(btnClear);
add(btnSave);
add(btnRestore);
Затем мы подключаем к этим кнопкам обработчики
событий:
btnClear.addActionListener(this);
btnSave.addActionListener(this);
btnRestore.addActionListener(this);
На последнем этапе инициализации создается
панель рисования класса DrawPanel, которая затем
добавляется в окно аплета:
dp = new DrawPanel();
add(dp);
Метод actionPerformed главного класса
Этот метод отвечает за обработку событий,
возникающих при нажатии кнопок, расположенных в
окне аплета.
Когда пользователь нажимает кнопку Clear, метод
actionPerformed удаляет панель рисования, а затем
создает и добавляет новую, запуская при этом
механизм размещения компонент системы Layout Manager:
if(dp != null)
{
this.remove(dp);
dp = new DrawPanel();
add(dp);
doLayout();
}
В том случае если пользователь нажал кнопку Save,
вызывается метод save класса DrawPanel, сохраняющий
нарисованное изображение в потоке:
else if(e.getSource().equals(btnSave))
{
dp.save();
}
Аналогично, для восстановления изображения
вызывается метод restore:
else if(e.getSource().equals(btnRestore))
{
dp.restore();
}
Затем окно аплета перерисовывается:
repaint();
Класс DrawPanel
Класс DrawPanel создан на базе класса Panel:
class DrawPanel extends Panel
implements MouseListener, MouseMotionListener
{
. . .
}
Он реализует интерфейсы MouseListener и MouseMotionListener,
необходимые для обработки событий, вызываемых
мышью.
Исходный текст класса с таким именем мы уже
описывали в примере "7.4.
Сохранение объекта Java в файле". Здесь мы
рассмотрим только отличия, связанные с
использованием потоков, созданных в оперативной
памяти.
В классе DrawPanel мы определили поля bSaveBuffer и baos:
static byte[] bSaveBuffer;
ByteArrayOutputStream baos;
Первое из них хранит ссылку на массив байт, в
который будет преобразовано содержимое
выходного потока после завершения процесса
записи, а второе - ссылку на выходной поток класса
ByteArrayOutputStream.
Метод save класса DrawPanel
При сохранении изображения мы сначала создаем
выходной поток в памяти как объект класса
ByteArrayOutputStream:
baos = new ByteArrayOutputStream();
Этот поток мы будем использовать для записи
объекта класса Vector, хранящего координаты
нарисованных линий.
Для того чтобы записать в поток ByteArrayOutputStream
объект класса Vector, мы создаем на базе этого
потока поток класса ObjectOutputStream:
ObjectOutputStream oos;
try
{
oos = new ObjectOutputStream(baos);
oos.writeObject(lines);
oos.close();
bSaveBuffer = baos.toByteArray();
}
catch (IOException ex)
{
System.out.println(ex.toString());
}
После создания потока ObjectOutputStream мы записываем
в него вектор lines и закрываем поток методом close.
Далее данные потока сохраняются в массиве
методом toByteArray. Этот метод динамически создает
массив подходящего размера и возвращает ссылку
на него. Мы сохраняем ссылку в поле bSaveBuffer, так как
она будет нам нужна для восстановления объекта
lines.
Метод restore класса DrawPanel
Восстановление нарисованного изображения
выполняется методом restore.
Прежде всего этот метод создает новый поток
ввода на базе массива bSaveBuffer:
ByteArrayInputStream bais;
bais = new ByteArrayInputStream(bSaveBuffer);
Этот поток размещается в оперативной памяти, а
не привязан к файлу.
Далее на базе потока класса ByteArrayInputStream мы
создаем поток ObjectInputStream и восстанавливаем из
него содержимое объекта lines:
ObjectInputStream ois;
try
{
ois = new ObjectInputStream(bais);
lines = (Vector)ois.readObject();
ois.close();
}
catch (IOException ex)
{
System.out.println(ex.toString());
}
catch (ClassNotFoundException ex)
{
System.out.println(ex.toString());
}
После восстановления lines нам необходимо
перерисовать окно аплета:
repaint();
Другие методы класса DrawPanel
Другие методы этого класса мы уже описывали в
разделе "7.4. Сохранение
объекта Java в файле".
Назад Вперед |