Назад
Вперед
7.2. Простейший редактор текста
В примере показано как можно сделать
простейший редактор текста с использованием
классов FileInputStream и FileOutputStream. Собственно
редактирование выполняется в окне объекта
класса TextArea.
Исходный текст примера
Архив проекта для Java WorkShop 2.0
Немного теории
Если приложение Java собирается работать с
файлами для выполнения операций
последовательного ввода или вывода, оно должно
создать для них объекты класса FileInputStream или
FileOutputStream. Прямой доступ к файлам выполняется с
помощью класса RandomAccessFile.
Класс FileInputStream предназначен для чтения данных
из файлов, а класс FileOutputStream - для записи данных в
файлы.
Оба класса имеют три конструктора:
public FileOutputStream(String name);
public FileOutputStream(File file);
public FileOutputStream(
FileDescriptor fdObj);
public FileInputStream(String name);
public FileInputStream(File file);
public FileInputStream(
FileDescriptor fdObj);
Первый конструктор класса FileOutputStream создает
выходной поток, связанный с файлом, путь к
которому передается через параметр name.
Аналогично, первый конструктор класса FileInputStream
создает выходной поток для файла, заданного
своим полным именем.
Остальные конструкторы позволяют создавать
потоки для файлов, заданных соответствующими
объектами классов File и FileDescriptor. Использование
этих классов мы проиллюстрируем в других
примерах нашей библиотеки.
При создании потоков на базе классов FileOutputStream и
FileInputStream могут возникать исключения FileNotFoundException,
SecurityException, IOException.
Создав выходной поток на базе класса FileOutputStream,
вы можете использовать для записи в него данных
три разновидности метода write, прототипы которых
представлены ниже:
public void write(byte b[]);
public void write(byte b[],
int off, int len);
public void write(int b);
Первый из этих методов записывает в поток
содержимое массива, ссылка на который передается
через параметр, начиная с текущей позиции в
потоке. После выполнения записи текущая позиция
продвигается вперед на число записанных байт,
которое при успешном завершении операции равно
длине массива (b.length).
Второй метод позволяет дополнительно указать
начальное смещение off записываемого блока данных
в массиве и количество записываемых байт len.
Третий метод просто записывает в поток один
байт данных.
Если в процессе записи происходит ошибка,
возникает исключение IOException.
Для входного потока, созданного на базе класса
FileInputStream, определены три разновидности метода read,
выполняющего чтение данных:
public int read();
public int read(byte b[]);
public int read(byte b[],
int off, int len);
Первая разновидность просто читает из потока
один байт данных. Если достигнут конец файла,
возвращается значение -1.
Вторая разновидность метода read читает данные в
массив, причем количество прочитанных данных
определяется размером массива. Метод возвращает
количество прочитанных байт данных или значение
-1, если в процессе чтения был достигнут конец
файла.
И, наконец, третий метод позволяет прочитать
данные в область массива, заданную своим
смещением и длиной.
Если при чтении происходит ошибка, возникает
исключение IOException.
После завершения операций с потоком его
необходимо закрыть методом close.
Описание примера
В главном окне нашего простейшего редактора
текста есть меню File со строками Open, Save и Save As,
которые действуют обычным образом (рис. 1).
Рис. 1. Главное окно простейшего редактора
текста
С помощью строки Open вы можете выбрать исходный
файл для редактирования, при этом на экране
появится стандартная диалоговая панель выбора
входного файла.
После редактирования файл можно сохранить под
текущем именем с помощью строки Save или под другим
именем (или в другом каталоге) с помощью строки Save
As.
Если выбрать строку Exit, работа редактора будет
завершена.
Рассмотрим исходный текст приложения. Так как
наш редактор создан на базе предыдущего примера,
мы заострим внимание только на существенных
отличиях.
Для работы с потоками ввода/вывода мы включили
в исходный текст приложения определение
библиотеки классов java.io.*:
import java.io.*;
Классы java.util.* нам нужны для разбора текстовой
строки:
import java.util.*;
Класс FrameWindow
Помимо полей для хранения ссылок на меню и
строки меню мы предусмотрели поле szCurrentFilename для
хранения полного пути к редактируемому файлу и
буфер buf для хранения содержимого редактируемого
файла:
String szCurrentFilename = "";
byte buf[];
Метод actionPerformed класса FrameWindow
При выборе из меню File строк Open, Save и Save As метод
actionPerformed вызывает, соответственно, методы FileOpen,
FileSave и FileSaveAs:
if(e.getSource().equals(miOpen))
{
FileOpen();
}
else if(e.getSource().equals(miSave))
{
FileSave();
}
else if(e.getSource().equals(miSaveAs))
{
FileSaveAs();
}
Все этим методы определены в нашем приложении.
Метод FileOpen класса FrameWindow
Внутри тела метода FileOpen мы определили
переменные fdlg и is:
FileDialog fdlg;
FileInputStream is = null;
Первое из них хранит ссылку на стандартную
диалоговую панель выбора исходного файла, а поле
is - ссылку на входной поток класса FileInputStream,
созданный для чтения этого файла.
Отображение указанной диалоговой панели
выполняется таким же образом, что и в предыдущем
примере:
fdlg = new FileDialog(this, "Open file",
FileDialog.LOAD);
fdlg.show();
if(fdlg.getDirectory() == null ||
fdlg.getFile() == null)
return;
Если пользователь отказался от выбора файла,
метод FileOpen возвращает управление. В противном
случае он записывает в поле szCurrentFilename полный путь
к исходному файлу:
szCurrentFilename = fdlg.getDirectory() +
fdlg.getFile();
Этот путь затем добавляется к заголовку
главного окна приложения:
setTitle("Simplest Java Notepad" + " - " +
szCurrentFilename);
Далее метод FileOpen пытается создать входной
поток для чтения файла:
try
{
is = new FileInputStream(
szCurrentFilename);
}
catch (FileNotFoundException ex)
{
System.out.println(ex.toString());
}
catch (SecurityException ex)
{
System.out.println(ex.toString());
}
Обратите внимание, что мы предусмотрели
раздельные обработчики исключений FileNotFoundException и SecurityException. При необходимости вы
можете использовать эти обработчики, например,
для выдачи разных сообщений об ошибке.
На следующем этапе наше приложение создает
буфер для чтения файла buf и читает в него файл
методом read:
try
{
buf = new byte[is.available()];
is.read(buf);
}
catch (IOException ex)
{
System.out.println(ex.toString());
}
Размер буфера мы определили с помощью метода
available, возвращающего количество байт данных,
доступных для чтения (то есть размер файла в
байтах).
В нашей программе мы не проверяем результат
чтения файла. Вы можете дополнить пример такой
проверкой, например, на тот случай, когда метод read
прочитает только часть данных. При этом вы должны
дочитать осташиеся данные в цикле.
Перед чтением содержимого файла и добавлением
его в окно редактирования мы удаляем предыдущее
содержимое из окна многострочного текстового
редактора ta. Для этого мы сначала выделяем весь
текст, который, возможно, есть в окне, а затем
заменяем его на пустую строку:
ta.selectAll();
ta.replaceRange(
"", 0, ta.getSelectionEnd());
Добавление нового текста, прочитанного из
файла, выполняется в цикле.
Перед его запуском мы преобразуем содержимое
буфера buf в текстовую строку и создаем разборщик
класса StringTokenizer для выделения символов возврата
каретки и перевода строки:
String szStr = new String(buf);
StringTokenizer st;
st = new StringTokenizer(szStr, "\r\n");
Цикл выглядит следующим образом:
while(st.hasMoreElements())
{
szStr = new String(
(String)st.nextElement());
ta.append(szStr + "\r\n");
}
Здесь мы извлекаем очередную строку, добавляем
к ней символы возврата каретки и перевода строки.
Далее мы добавляем результат в окно редактора ta.
Перед тем как вернуть управление, метод FileOpen
закрывает входной поток:
try
{
is.close();
}
catch (IOException ex)
{
System.out.println(ex.toString());
}
Метод FileSave класса FrameWindow
Этот метод сохраняет отредактированный файл
под прежним именем, записанным в поле szCurrentFilename.
Как он работает?
Внутри тела метода определена переменная os
класса FileOutputStream:
FileOutputStream os = null;
В ней будет хранится ссылка на выходной поток,
связанный с сохраняемым файлом.
Перед сохранением файла метод FileSave получает
текущее содержимое окна редактирования текста и
преобразует его в массив байт:
String sz = ta.getText();
buf = sz.getBytes();
Далее метод создает выходной поток класса
FileOutputStream, записывает в него содержимое
обновленного буфера buf и закрывает поток методом
close:
try
{
os = new FileOutputStream(
szCurrentFilename);
os.write(buf);
os.close();
}
catch (IOException ex)
{
System.out.println(ex.toString());
}
catch (SecurityException ex)
{
System.out.println(ex.toString());
}
Здесь мы предусмотрели обработку исключений
IOException и SecurityException. Они могут возникнуть в
процессе записи в случае ошибок ввода/вывода или
при появлении проблем с правами доступа.
Метод FileSaveAs класса FrameWindow
С помощью этого метода приложение может
сохранить файл в другом каталоге или под другим
именем.
Прежде всего метод выводит на экран диалоговую
панель для выбора пути и имени сохраняемого
файла:
FileDialog fdlg;
fdlg = new FileDialog(
this, "Save file as...",
FileDialog.SAVE);
fdlg.show();
Новый путь записывается в поле szCurrentFilename, при
этом метод FileSaveAs дополнительно изменяет и
заголовок главного окна приложения:
szCurrentFilename = fdlg.getDirectory() +
fdlg.getFile();
setTitle("Simplest Java Notepad" + " - " +
szCurrentFilename);
Теперь для сохранения файла в новом месте
достаточно вызвать только что рассмотренный
метод FileSave:
FileSave();
Назад Вперед |