Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых
[Назад]

Библиотека примеров приложений Java

Оглавление
Выбор файлов
Простейший редактор текста
Копирование файлов UNICODE
Сохранение объекта Java в файле
Произвольные классы и файлы
Буферизация потоков
Разбор конфигура-
ционного файла

Работа с консолью
Работа с классом PrintWriter
Разбор строк класса String
Загрузка и просмотр изображений
Потоки в оперативной памяти
Конвейерные потоки
Комбинирование двух потоков
Комбинирование нескольких потоков
Поиск слова в текстовом файле
Произвольный доступ к файлу
Информация о файле
Работа с каталогами
Просмотр содержимого каталога
Просмотр каталога с фильтром
Панель для выбора каталога
Список системных свойств
Сохранение списка системных свойств
Контрольная сумма файла
Копирование, переименование, удаление файлов
Архивы ZIP
Создание архива ZIP
Распаковка архива ZIP
Обход дерева каталогов

Назад Вперед

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).

pic1.gif (5176 bytes)

Рис. 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(); 

Назад Вперед

[Назад]