ROBOWEB : Документация : Документация по JAVA , описание JAVA , примеры JAVA , программирование на JAVA , JAVA аплеты , исходники , исходные тексты , source , make программ на JAVA , библиотека классов JAVA , Java WorkShop , Java Studio , компоненты JAVA , свойства события методы JAVA , сокет , передача данных , потоковые сокеты , доступ к файлам , датаграммные сокеты , растровое изображение , видео , звуковые файлы , sun взлом защита скачать бесплатно новые свежие архив секреты недокументированные способы русский перевод компьютер zip каталог add url forum форум чат chat программист программер хакер xakep hack баги компилить сорцы научиться урок обучение домашняя страница home page разработка создание применение примеры способы портал документ знания
Разработка сайтов, web дизайн - Центр Русского Дизайна HOD.RU
FLASH
3D Studio MAX
DreamWeawer FAQ
Изучение HTML
META тэги
CSS
Руководство по стилям
Спецификация WML (WAP)
Язык DHTML
Спецификация XML
Руководство по Java
Документация по JavaScript
Язык HOD Text Processor
Интерфейс CGI
Документация по Perl 5
Perl FAQ
Документация по PHP
PHP/FI 2.0
Документация по SQL
Базы данных
Доступ к БД

Рейтинг@Mail.ru Rambler's Top100

Веб дизайнеру
Каталог сайтов Axes.ru


Приложение DirectFile

 

Для иллюстрации способов работы с классом RandomAccessFile мы подготовили приложение DirectFile, в котором создается небольшая база данных. Эта база данных состоит из двух файлов: файла данных и файла индекса.

В файле данных хранятся записи, сосотящие из двух полей - текстового и числового. Текстовое поле с названием name хранит строки, закрытые смиволами конца строки "\r\n", а числовое с названием account - значения типа int.

В меню File нашего приложения есть строки New и View records.

С помощью строки New вы можете создать базу данных, состоящую из трех записей. Если выбрать из меню File строку View records, на экране появится диалоговая панель с содержимым этих записей.

Вместо символа перевода строки в диалоговой панели отображается маленький квадратик.

Из этого дампа видно, что после первого запуска приложения в файле данных имеются следующие записи:

Номер записи

Смещение в файле данных

Поле name

Поле account

0

0

Ivanov

1000

1

12

Petrov

2000

2

24

Sidoroff

3000

При последующих запусках каждый раз в файл данных будут добавляться приведенные выше записи.

Так как поле name имеет переменную длину, для обеспечения возможности прямого доступа к записи по ее номеру необходимо где-то хранить смещения всех записей. Мы это делаем в файле индексов.

Файл индексов хранит 8-байтовые смещения записей файла данных в формате long. Зная номер записи, можнор легко вычислить смещение в файле индексов, по которому хранится смещение нужной записи в файле данных. Если извлечь это смещение, то можно выполнить позиционирование в файле данных с целью чтения нужной записи, что и делает наше приложение.

Исходный текст приложения DirectFile

Исходный текст приложения DirectFile представлен в листинге 2.

Листинг 2. Файл DirectFile.java

import java.awt.*;
import java.io.*;
import java.util.*;
public class DirectFile
{
  public static void main(String args[])
  {
    MainFrameWnd frame =
      new MainFrameWnd("MenuApp");
    frame.setSize(
    frame.getInsets().left +
      frame.getInsets().right  + 320,
      frame.getInsets().top  +
      frame.getInsets().bottom + 240);
    frame.show();
  }
}
class MainFrameWnd extends Frame
{
  MenuBar mbMainMenuBar;
  Menu mnFile;
  Menu mnHelp;
  boolean fDBEmpty = true;
  public MainFrameWnd(String sTitle)
  {
    super(sTitle);
    setSize(400, 200);
    setBackground(Color.yellow);
    setForeground(Color.black);
    setLayout(new FlowLayout());
    mbMainMenuBar = new MenuBar();
    mnFile = new Menu("File");
    mnFile.add("New...");
    mnFile.add("View records...");
    mnFile.add("-");
    mnFile.add("Exit");
    mnHelp = new Menu("Help");
    mnHelp.add("Content");
    mnHelp.add("-");
    mnHelp.add("About");
    mbMainMenuBar.add(mnFile);
    mbMainMenuBar.add(mnHelp);
    setMenuBar(mbMainMenuBar);
  }
  public void paint(Graphics g)
  {
    g.setFont(new Font("Helvetica",
      Font.PLAIN, 12));
    g.drawString("Frame window", 10, 70);
    super.paint(g);
  }
  public boolean handleEvent(Event evt)
  {
    if(evt.id == Event.WINDOW_DESTROY)
    {
      setVisible(false);
      System.exit(0);
      return true;
    }
    else
      return super.handleEvent(evt);
  }
  public boolean action(Event evt,
   Object obj)
  {
    MenuItem mnItem;
    if(evt.target instanceof MenuItem)
    {
      mnItem = (MenuItem)evt.target;
      if(obj.equals("Exit"))
      {
        System.exit(0);
      }
      else if(obj.equals("New..."))
      {
	if(fDBEmpty)
 	{
	  SimpleDBMS db = new SimpleDBMS(
	    "dbtest.idx", "dbtest.dat");
          db.AddRecord("Ivanov",   1000);
          db.AddRecord("Petrov",   2000);
	  db.AddRecord("Sidoroff", 3000);
          db.close();
	  fDBEmpty = false;
          MessageBox mbox;
          mbox = new MessageBox(
            "Database created",
            this, "Information", true);
	  mbox.show();
	}
      }
      else if(obj.equals("View records..."))
      {
        SimpleDBMS db = new SimpleDBMS(
	  "dbtest.idx", "dbtest.dat");
        String szRecords;
	
	szRecords =
          db.GetRecordByNumber(0) +
	  db.GetRecordByNumber(1) +
	  db.GetRecordByNumber(2);
	
        db.close();
	
        MessageBox mbox;
        mbox = new MessageBox(szRecords,
          this, "Database records", true);
	mbox.show();
      }

      else if(obj.equals("Content"))
      {
        MessageBox mbox;
        mbox = new MessageBox(
          "Item Content selected",
          this, "Dialog from Frame", true);
        mbox.show();
      }

      else if(obj.equals("About"))
      {
        MessageBox mbox;
        mbox = new MessageBox(
          "Item About selected",
          this, "Dialog from Frame", true);
        mbox.show();
      }
      else
        return false;
      return true;
    }
    return false;
  }
}
class MessageBox extends Dialog
{
  Label lbMsg;
  Button btnOK;
  public MessageBox(String sMsg,
    Frame  parent, String  sTitle,
    boolean  modal)
  {
    super(parent, sTitle, modal);
    resize(300, 100);
    setLayout(new GridLayout(2, 1));
    lbMsg = new Label(sMsg, Label.CENTER);
    add(lbMsg);
    btnOK = new Button("OK");
    add(btnOK);
  }
  public boolean handleEvent(Event evt)
  {
    if(evt.id == Event.WINDOW_DESTROY)
    {
      dispose();
      return true;
    }
    else
      return super.handleEvent(evt);
  }
  public boolean action(Event evt,
   Object obj)
  {
    Button btn;
    if(evt.target instanceof Button)
    {
      btn = (Button)evt.target;
      if(evt.target.equals(btnOK))
      {
        dispose();
      }
      else
        return false;
      return true;
    }
    return false;
  }
}
class SimpleDBMS
{
  RandomAccessFile idx;
  RandomAccessFile dat;
  long idxFilePointer = 0;
  public SimpleDBMS(String IndexFile,
   String DataFile)
  {
    try
    {
      idx = new RandomAccessFile(
        IndexFile, "rw");
      dat = new RandomAccessFile(
        DataFile, "rw");
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
  }
  public void close()
  {
    try
    {
      idx.close();
      dat.close();
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
  }
  public void AddRecord(String name,
     int account)
  {
    try
    {
      idx.seek(idx.length());
      dat.seek(dat.length());
      idxFilePointer = dat.getFilePointer();
      idx.writeLong(idxFilePointer);
      dat.writeBytes(name+ "\r\n");
      dat.writeInt(account);
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
  }
  public String GetRecordByNumber(long nRec)
  {
    String sRecord = "<empty>";

    try
    {
      Integer account;
      String str = null;
      idx.seek(nRec * 8);
      idxFilePointer = idx.readLong();
      dat.seek(idxFilePointer);
      str = dat.readLine();
      account = new Integer(dat.readInt());
      sRecord = new String("> " +
       account + ", " + str);
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
    return sRecord;
  }
}

Описание исходного текста приложения DirectFile

Для работы с базой данных мы создали класс SimpleDBMS, определив в нем конструктор, методы для добавления записей, извлечения записей по их порядковому номеру, а также метод для закрытия базы данных.

Создание базы данных

Когда пользователь выбирает из меню File строку New, соответствующий обработчик события создает базу данных, передавая конструктору имена файла индекса dbtest.idx и файла данных dbtest.dat:

SimpleDBMS db = new SimpleDBMS(
  "dbtest.idx", "dbtest.dat");

После этого с помощью метода AddRecord, определенного в классе SimpleDBMS, в базу добавляются три записи, состоящие из текстового и числового полей:

db.AddRecord("Ivanov",   1000);
db.AddRecord("Petrov",   2000);
db.AddRecord("Sidoroff", 3000);

После завершения работы с базой данных она закрывается методом close из класса SimpleDBMS:

db.close();

Просмотр записей базы данных

При выборе строки View records из меню File приложение открывает файл базы данных:

SimpleDBMS db = new SimpleDBMS(
  "dbtest.idx", "dbtest.dat");

Затем оно извлекает три записи с номерами 0, 1 и 2, вызывая для этого метод GetRecordByNumber, также определенный в классе SimpleDBMS:

String szRecords;

szRecords = db.GetRecordByNumber(0) +
  db.GetRecordByNumber(1) +
  db.GetRecordByNumber(2);

Записи объединяются и сохраняются в переменной szRecords типа String. После этого база данных закрывается:

db.close();

Для отображения содержимого записей мы создаем диалоговую панель на базе определенного нами класса MessageBox:

MessageBox mbox;
mbox = new MessageBox(szRecords,
  this, "Database records", true);
mbox.show();

Класс SimpleDBMS

Рассмотрим теперь класс SimpleDBMS.

В этом классе определено три поля с именами idx, dat и idxFilePointer, а также три метода.

Поля класса SimpleDBMS

Поля idx и dat являются объектами класса RandomAccessFile и представляют собой, соответственно, ссылки на файл индекса и файл данных. Поле idxFilePointer типа long используется как рабочее и хранит текущее смещение в файле.

Конструктор класса SimpleDBMS

Конструктор класса SimpleDBMS выглядит достаточно просто. Все, что он делает, - это создает два объекта класса RandomAccessFile, соответственно, для индекса и данных:

idx = new RandomAccessFile(IndexFile, "rw");
dat = new RandomAccessFile(DataFile, "rw");

Так как в качестве второго параметра конструктору класа RandomAccessFile передается строка "rw", файлы открываются и для чтения, и для записи.

Метод close

Метод close закрывает файлы индекса и данных, вызывая метод close из класса RandomAccessFile:

idx.close();
dat.close();

Метод AddRecord

Метод AddRecord добавляет новую запись в конец файла данных, а смещение этой записи - в конец файла индекса. Поэтому перед началом своей работы текущая позиция обоих указанных файлов устанавливается на конец файла.

Для установки мы применили метод seek из класса RandomAccessFile, передав ему в качестве параметра значение длины файла в байтах, определенное при помощи метода length из того же класса:

idx.seek(idx.length());
dat.seek(dat.length());

Перед тем как добавлять новую запись в файл данных, метод AddRecord определяет текущую позицию в файле данных (в данном случае это позиция конца файла) и записывает эту позицию в файл индекса:

idxFilePointer = dat.getFilePointer();
idx.writeLong(idxFilePointer);

Далее метод AddRecord выполняет сохранение полей записи в файле данных. Для записи строки вызывается метод writeBytes, а для записи численного значения типа int - метод writeInt:

dat.writeBytes(name + "\r\n");
dat.writeInt(account);

Обратите внимение, что к строке мы добавляем символы возврата каретки и перевода строки. Это сделано исключительно для того чтобы обозначить конец строки текстового поля.

Метод GetRecordByNumber

Метод GetRecordByNumber позволяет извлечь произвольную запись из файла данных по ее порядковому номеру.

Напомним, что смещения всех записей хранятся в файле индексов и имеют одинаковую длину 8 байт. Пользуясь этим, метод GetRecordByNumber вычисляет смещение в файле индекса простым умножением порядкового номера записи на длину переменной типа long, то есть на 8 байт, а затем выполняет позиционирование:

idx.seek(nRec * 8);

После этого метод GetRecordByNumber извлекает из файла индексов смещение нужной записи в файле данных, вызывая для этого метод readLong, а затем выполняет позиционирование в файле данных:

idxFilePointer = idx.readLong();
dat.seek(idxFilePointer);

Поля записи читаются из файла данных в два приема. Вначале читается строка текстового поля, а затем - численное значение, для чего вызываются, соответственно, методы readLine и readInt:

str = dat.readLine();
account = new Integer(dat.readInt());

Полученные значения полей объединяются в текстовой строке и записываются в переменную sRecord:

sRecord = new String("> " +
  account + ", " + str);

Содержимое этой переменной метод GetRecordByNumber возвращает в качестве извлеченной строки записи базы данных.





Содержание