RWFileManager
Class
RWFileManager allocates, deallocates, and coalesces free space in a disk file. This is done internally by maintaining on disk a linked-list of free space blocks. Two typedefs are used:
typedef long RWoffset;
typedef unsigned long RWspace;
The type
RWoffset is used for the offset within the file to the start of a storage space;
RWspace is the amount of storage space required. The actual typedef may vary depending on the system you are using.
Class
RWFile is a public base class of class
RWFileManager; therefore, the public member functions of class
RWFile are available to class
RWFileManager.
Construction
The
RWFileManager constructor has the prototype:
RWFileManager(const char* filename);
The argument is the name of the file that the
RWFileManager is to manage. If it exists, it must contain a valid
RWFileManager; otherwise, one will be created.
Member Functions
The class
RWFileManager adds four additional member functions to those of class
RWFile. They are:
1. RWoffset allocate(RWspace s);
Allocates s bytes of storage in the file, returning the offset to the start of the allocation.
2. void deallocate(RWoffset t);
Deallocates (frees) the storage space starting at offset t. This space must have been previously allocated by the function allocate().
3. RWOffset endData();
Returns the offset to the last data in the file.
4. RWoffset start();
Returns the offset from the start of the file to the first space ever allocated by
RWFileManager, or returns
RWNIL if no space has been allocated, which implies that this is a new file.
RWNIL is a macro whose actual value is system dependent. Typically, it is
-1L.
The statement:
RWoffset a = F.allocate(sizeof(double));
uses
F of
RWFileManager to allocate the space required to store an object with the size of a double, and returns the offset to that space. To write the object to the disk file, you should seek to the allocated location and use
Write(). It is an error to read or write to an unallocated location in the file.
It is your responsibility to maintain a record of the offsets necessary to read the stored object. To help you do this, the first allocation ever made by an
RWFileManager is considered special and can be returned by member function
start() at any time. The
RWFileManager will not allow you to deallocate it. This first block will typically hold information necessary to read the remaining data, perhaps the offset of a root node, or the head of a linked-list.
Example
The following example shows the use of class
RWFileManager to construct a linked-list of
int s on disk. The source code is included in the
buildspace\examples\tools directory as
fmgrsave.cpp and
fmgrrtrv.cpp. When using this example, you must type a carriage return after the last item you want to insert in order to guarantee that it will be added to the list. This is because different compilers handle the occurrence of an EOF on the
cin stream differently.
#include <rw/filemgr.h> // 1
#include <rw/rstream.h>
struct DiskNode { // 2
int data; // 3
Rwoffset nextNode; // 4
};
int main(){
RWFileManager fm("linklist.dat"); // 5
// Allocate space for offset to start of the linked list:
fm.allocate(sizeof(RWoffset)); // 6
// Allocate space for the first link:
RWoffset thisNode = fm.allocate(sizeof(DiskNode)); // 7
fm.SeekTo(fm.start()); // 8
fm.Write(thisNode); // 9
DiskNode n;
int temp;
RWoffset lastNode;
std::cout << "Input a series of integers, ";
std::cout << "then EOF to end:\n";
while (std::cin >> temp) { // 10
n.data = temp;
n.nextNode = fm.allocate(sizeof(DiskNode)); // 11
fm.SeekTo(thisNode); // 12
fm.Write(n.data); // 13
fm.Write(n.nextNode);
lastNode = thisNode; // 14
thisNode = n.nextNode;
}
fm.deallocate(n.nextNode); // 15
n.nextNode = RWNIL; // 16
fm.SeekTo(lastNode);
fm.Write(n.data);
fm.Write(n.nextNode);
return 0;
} // 17
Here is a line-by-line description of the program:
Having created the linked-list on disk, how might you read it? Here is a program that reads the list and prints the stored integer field:
#include <rw/filemgr.h>
#include <rw/rstream.h>
struct DiskNode {
int data;
RWoffset nextNode;
};
int main(){
RWFileManager fm("linklist.dat"); // 1
fm.SeekTo(fm.start()); // 2
RWoffset next;
fm.Read(next); // 3
DiskNode n;
while (next != RWNIL) { // 4
fm.SeekTo(next); // 5
fm.Read(n.data); // 6
fm.Read(n.nextNode);
std::cout << n.data << "\n"; // 7
next = n.nextNode; // 8
}
return 0;
} // 9
And this is a line-by-line description of the program: