sis.db.DataFile


 package sis.db; import java.util.*; import java.io.*; import sis.util.*; public class DataFile {    public static final String DATA_EXT = ".db";    public static final String KEY_EXT = ".idx";    private String dataFilename;    private String keyFilename;    private RandomAccessFile db;    private KeyFile keys;    public static DataFile create(String filebase) throws IOException {       return new DataFile(filebase, true);    }    public static DataFile open(String filebase) throws IOException {       return new DataFile(filebase, false);    }    private DataFile(String filebase, boolean deleteFiles)          throws IOException {       dataFilename = filebase + DATA_EXT;       keyFilename = filebase + KEY_EXT;       if (deleteFiles)          deleteFiles();       openFiles();    }    public void add(String key, Object object) throws IOException {       long position = db.length();       byte[] bytes = getBytes(object);       db.seek(position);       db.write(bytes, 0, bytes.length);       keys.add(key, position, bytes.length);    }    public Object findBy(String id) throws IOException {       if (!keys.containsKey(id))          return null;       long position = keys.getPosition(id);       db.seek(position);       int length = keys.getLength(id);       return read(length);    }    public int size() {       return keys.size();    }    public void close() throws IOException {       keys.close();       db.close();    }    public void deleteFiles() {       IOUtil.delete(dataFilename, keyFilename);    }    private Object read(int length) throws IOException {       byte[] bytes = new byte[length];       db.readFully(bytes);       return readObject(bytes);    }    private Object readObject(byte[] bytes) throws IOException {       ObjectInputStream input =          new ObjectInputStream(new ByteArrayInputStream(bytes));       try {          try {             return input.readObject();          }          catch (ClassNotFoundException unlikely) {             // but write a test for it if you must             return null;          }       }       finally {          input.close();       }    }    private void openFiles() throws IOException {       keys = new KeyFile(keyFilename);       db = new RandomAccessFile(new File(dataFilename), "rw");    }    private byte[] getBytes(Object object) throws IOException {       ByteArrayOutputStream byteStream = new ByteArrayOutputStream();       ObjectOutputStream outputStream =          new ObjectOutputStream(byteStream);       outputStream.writeObject(object);       outputStream.flush();       return byteStream.toByteArray();    } } 

The DataFile class is the core part of the solution. It demonstrates use of a RandomAccessFile object, which you store in the instance variable db (short for database, one of the small number of abbreviations I use). You create a RandomAccessFile object by passing in a File object and a String declaring the mode in which you wish to access the RandomAccessFile.

RandomAccessFile provides four modes: "r" (read-only), "rw" (read and write access), "rws" (read-write with synchronous data/metadata updates), and "rwd" (read-write with synchronous data updates). The synchronous updates ensure that updates to the file are safely written to the underlying storage device. Without using them, you could conceivably lose data in a system crash. The "rws" option ensures persistence of both content and metadata (information such as the last modified timestamp for the file), while the "rwd" option only ensures updates of the content.

Here we chose the "rw" option, since you want to be able to both read data from and write data to the data file. The other read-write options incur additional overhead but may be necessary to maintain data integrity.

You use the seek method to rapidly move an internal file pointer to any location within the underlying file. The getFilePointer method (not used here) returns the current position of the file pointer. The length method returns the total number of bytes in the file. Like other IO classes, RandomAccessFile supplies many read and write methods to extract and store data.

RandomAccessFile does not directly support storing objects. In order to persist an object to the RandomAccessFile, you must first convert it to a byte array. To convert an object to bytes, the getBytes method wraps a ByteArrayOutputStream in an ObjectOutputStream. This means that any objects written to the ObjectOutputStream are piped to the underlying ByteArrayOutputStream. You can extract the bytes from an ByteArrayOutputStream by sending it the toByteArray message.

To read an object from the RandomAccessFile, you must do the opposite. Create a byte array of the appropriate length and use the method readFully to populate the bytes from the RandomAccessFile. Wrap the populated byte array in a ByteArrayInputStream, which you then wrap in an ObjectInputStream. Reading from the ObjectInputStream will reconstitute the persisted object using the underlying bytes.



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net