Binary Files

advertisement
106742802
1
Chapter 14
Binary Files
Bitsets
106742802
2
Binary Files
Hardware level - file data records are stored on a disk in fixed-length data blocks
(normally non-contiguous) .
Logical View - sequence of records
A text file contains ASCII characters with a newline sequence separating lines
A binary file soncists of data objects that vary from a single character (byte) to more
complex structures that include integers, floating-point values, programmer-generated
class objects, and arrays.
The Operating system allows a programmer to read and write individual data records and
Maintains a file pointer.
File systems allow direct access - measures the current position as an offset from
the beginning of the file in number of bytes.
File Pointer - maintains current position in the file
File as a direct access structure:
R0
R1
R2
R3
Rn-1
106742802
3
The fstream class
The C++ fstream class describes file objects that can be used for both - input and output
When creating the object the open method is used to attach a physical file named and
access mode.
Mode
ios::in
ios::out
ios::trun
ios::nocreate
ios::binary
Action
open file for reading
open file for writing
erase file records before reading or writing
if the file does not exist, do not crate an empty file.
return a stream error condition.
open file in binary mode not a text file
#include <iostream>
#include <fstream>
1.
fstream
f;
// open textfile “ Phone” for input. If the file does not already exist, indicate
// an error condition
f.open ( “Phone”, ios::in | ios:: nocreate );
2.
fstream f;
// open a binary file for input and output
f.open ( “ DataBase”, ios::in | ios::out | ios::binary );
tellg() - returns in bytes the location of the current file pointer as an offset from the
beginning of the file for an input file
tellp( ) - returns in bytes the location of the current file pointer for an output file
seekp( ) and seekg( ) - allow the user to reposition the current file pointers.
The seek functions take an offset parameter that measures the number of bytes from the
beginning (beg), ending (end) , or current position (cur ).
If the file is for both, input and output use the seek functions tellg and seekg..
106742802
4
Program 14-3
#ifndef ACCOUNT_CLASS
#define ACCOUNT_CLASS
#include <iostream>
using namespace std;
// maintain bank account information
class account
{
public:
account (int n = 0, double bal = 0.0): acctNo(n), balance (bal)
{}
// update balance with deposit (D) or withdrawal (W)
void update (char type, double amt)
{
if (type == 'D')
balance += amt;
else
balance -= amt;
}
// output account
friend ostream& operator<< (ostream& ostr, const account& acct)
{
ostr << acct.acctNo << ": " << acct.balance;
return ostr;
}
private:
int acctNo;
double balance;
};
#endif// ACCOUNT_CLASS
106742802
// File: prg14_3.cpp
// program reads and writes account records to and from file
// accounts.dat"; initial write creates 5 records in file with
// account numbers 0 to 4. user is prompted to enter a series of
// account numbers, transactions (deposit 'D'/withdrawal 'W'), and
// amounts. corresponding account is read from file and updated
// based on transaction type. resulting data is then written back
// to the file. program concludes by displaying current account
// information after user enters account number -1
#include <iostream>
#include <fstream>
#include "d_acct.h"
using namespace std;
// output the records in a binary file of account objects
void outputAccounts(fstream& f);
int main()
{
// binary file of part values
fstream acctFile;
account acct;
int i, n;
char type;
double amt;
// open binary file for input and output. truncate earlier version
acctFile.open("accounts.dat",ios::in | ios::out |
ios::trunc | ios::binary);
if (!acctFile)
{
cerr << "Cannot create 'accounts.dat'" << endl;
exit(1);
}
5
106742802
6
// File: prg14_3.cpp ( continued)
// write 5 records with account number 0, 1, ..., 4
for (i=0;i < 5;i++)
{
acct = account(i);
acctFile.write((char *)&acct, sizeof(account));
}
// ask user to input account number and 'D' for deposit
// and 'W' for withdrawal along with the ammount
// update a record of the file; terminate with accout number -1
while(true)
{
cout << "Enter acct#, type (D or W), and amount: ";
cin >> n;
if (n == -1)
break;
cin >> type >> amt;
// seek to record n
acctFile.seekg(n*sizeof(account), ios::beg);
// read the record and update the balance
acctFile.read((char *)&acct, sizeof(account));
acct.update(type, amt);
// seek back to the previous record
acctFile.seekg(-int(sizeof(account)), ios::cur);
acctFile.write((char *)& acct, sizeof(account));
}
// output final state of the account database
cout << endl << "Final state of the accounts" << endl;
outputAccounts(acctFile);
return 0;
}
106742802
// File: prg14_3.cpp ( continued )
void outputAccounts(fstream& f)
{
account acct;
// go to the end of the file
f.seekg(0, ios::end);
// n = number of records in the file
int n = f.tellg()/sizeof(account), i;
// go back to the beginning of the file
f.seekg(0, ios::beg);
// read and output n records
for (i=0; i < n; i++)
{
f.read((char *)& acct, sizeof(account));
cout << acct << endl;
}
}
/*
Run:
Enter acct#, type (D or W), and amount: 3 D 200.00
Enter acct#, type (D or W), and amount: 1 D 500.00
Enter acct#, type (D or W), and amount: 4 W 150.00
Enter acct#, type (D or W), and amount: 2 D 800.00
Enter acct#, type (D or W), and amount: 4 D 225.00
Enter acct#, type (D or W), and amount: 2 W 475.00
Enter acct#, type (D or W), and amount: 1 W 100.00
Enter acct#, type (D or W), and amount: -1
Final state of the accounts
0: 0
1: 400
2: 325
3: 200
4: 75
*/
7
106742802
8
BINARY CLASS SPECIFICATION
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
#include “strclass.h”
enum Access { IN, OUT, INOUT } ; // file access types
enum SeekType { Beg, CUR, END } ; // type of seeks that can be performed
template < class T>
class BinFile {
private:
fstream f ;
Access accessType;
String Fname;
int fileOpen;
// C++ stream object with its name and access type
// file access type
// physical file name
// is the file open?
// parameter measuring file as a direct access structure
int Tsize;
// size of data record
int fileSize;
// number of file records
// prints an error message and terminates the program
void error ( char * msg );
public:
// constructors and destructors
BinFile ( const String& fileName, Access atype = OUT );
~BinFile(void);
BinFile(BinFile<T>& bf); // copy constructor - terminates programs
// not allowed
// file utility methods
void Clear ( void );
// truncate records in the file - leaves file open
void Delete(void); // close file and remove it from the file system
void Close ( void );
// close the file
int EndFile ( ); // tests EOF condition - for IN files - otherwise use loop to control writes
long Size ();
// returns number of file records
void Reset (void);
// reset the file to first record
void Seek ( long pos, SeekType mode );
int Read( T *a, int A );
// block read of n data values into address A
int Write ( T *A, int n ); // block write
T peek ( void ); // value of record at current location
void Write ( const T& data, long post );// copy data to record at index pos
T Read ( long post );
// read record from index position
void Append ( T item ); // write a record at the end of file
};
Version 1.0.0
Draft - January 8, 1995
kfv-COD
CIS-246 ADVANCED C++ COURSE PACKET
13-29
106742802
BINFILE IMPLEMENTATION ( for complete implementation see binfile.h)
// constructor
template < class T>
BinFile<T>::BinFile ( const String& fileName, Access atype )
{
// stream open operations
// for IN, a file is not created if it does not exist
// for OUT , any existing data are thrown away ( truncated )
// for INOUT , the file has input and output capability.
if ( atype == IN )
fopen ( fileName, ios :: in | ios::nocreate | ios :: binary );
else if ( atype == OUT )
fopen ( filename, ios::out | ios::trunc | ios ::binary );
else
fopen ( fileName, ios ::in | ios::out | ios :: binary );
if ( ! f )
Error ( “binFile constructor : file cannot be opened “ );
else
fileOpen = 1;
accessType = atype;
// Compute number of records in the file
// Tsize is the number of bytes in the data type
Tsize = sizeof ( T );
if ( accessType == IN ) || accessType == INOUT )
f.seekg( 0, ios::end );
fileSize =f.tellg ( ) / Tsize;
f.seekg ( 0, ios::beg );
}
else
filesize = 0; // size for OUT file
// record physical file name
fname = fileName;
}
9
106742802
10
File Access - Read
// read a record from the file - read takes the position parameter and by combining the
data
// size and position parameter and using seekg locates the current file pointer and extracts
// the data value
template < class T >
T BinFile<T> :: Read ( long pos )
{
T data;
if ( !fileOpen )
Error (“ BinFile” Read ( int pos ) : file closed “ );
// read method invalid with OUT only file
if ( accessType == OUT )
Error ( “Invalid file access operation “ );
else If ( pos < 0 || pos >= fileSize ) // test range 0 - fileSize-1
Error (“invalid file access operation “ );
// position the current file pointer and extract data using the fstream read method
f.seekg ( pos * Tsize , ios::beg );
f.read ( (char * ) & data, Tsize ) ;
// if the access mode is IN and we have read all records, set the stream to EOF
if ( accessType == IN )
if ( f.tellg ( ) / Tsize >= fileSize )
f.clear ( ios :: eofbit ) ; // sets EOF bit
return data;
}
106742802
11
File Access - Write
// writes an en-element list from array A to the file
template < class T >
void BinFile <T> :: Write ( T *A, int n )
{
long previousRecords;
// write is invalid with an IN only file
if ( accessType == IN ) Error ( “Invalid file access operation “);
if ( !fileOpen ) Error ( “binFile Write ( T* a, int n ) : file closed “);
// compute the new file size, call tellg( ) to compute number of file records prior to
// output point. determine if file size will expand. if so, increment fileSize by the
// number of records that will be added.
peviousRecords - f.tellp ( ) / Tsize ;
if ( previousRecords + n > fileSize )
fileSize += previousRecords + n - fileSize;
// the number of bytes to write is n * Tsize;
f.write ( ( char * ) A, Tsize * n );
}
Utility Method - Clear
//Clear deletes file records by closing and then opening file
template < class T>
void BinFile <T>::Clear ( void )
{
// an IN file cannot be cleared
if ( accessType == IN )
Error ( “Invalid file access operation “ );
// close and then open file
f.close ( ) ;
if ( accessType == OUT )
f.open ( fname, ios::out | ios::trunc | ios::binary );
else
f.open ( fname, ios :: in | ios :: out | ios :: trunc | ios :: binary );
if ( !f )
Error ( “BinFile Clear : cannot reopen the file “ );
fileSize = 0;
}
106742802
12
BITSETS
C++ allows manipulation of individual bits with the bit-wise operators
OR
|
AND
&
NOT
~
EOR
^
(inclusive or)
(exclusive or )
It also provides bit shift operators – typically used with unsigned numbers
shift left
<<
x << n
multiplies x by 2n
x>>n
dividex x by 2n
shifting to the left fills vacated bits with 0
shift right
>>
For unsigned numbers- shifting to the right fills vacated bits with 0
For signed numbers – shifting to the right fills vacated bits with 1
Example:
Unsigned char x = 182, y = 154;
In binary: x = 10110110 , y = 10011010
a)
x
10110110
|y
10011010
10111110
b)
x
10110110
&y
10011010
10010010
Bit shift operations:
x = 10110110 X << 1
y = 10011010 y >> 2
= 01011010
= 00101101
c)
x
10110110
^y
10011010
00101100
106742802
13
Bitmaps
Bitmaps are useful for managing a collection of resources of any type.
For example, to determine if a resource is in use, you need to store only one bit of
information per resource.
Assume the figure below represents a file of records:
Record 1
Record 2
Record 3
Record 4
Record 5
Each record is of the same size ( it could be a char, int , or object of any type)
If a record is deleted and you want to add a new record you should reuse the empty space.
You could keep a free list to determine the empty locations in the file.
An alternative you could maintain another file called a bitmap.
Bitmap
10101000
00000000
00000000
00000000
The bitmap has one bit associated with each record in the file, grouped together in banks
of 32 bits.
106742802
14
Allocation using a bitmap:
long FindEmpty()
{
openbit(); // open file that contains bitmap
while ( (bank_no = read_bank(&bank)) != END_OF_BITMAP )
{
// if room left in bank
if ( (offset = find_set_next_zero( & bank)) != BANK_FULL)
{
return ( (long) ( bank * BITS_IN_LONG + offset ));
}
}
bank_no = alloc_bank(&bank); allocate new bank
offset = find_set_next_zero(&bank); //
turn on first bit
assert( offset == 0L);
return (long)(bank * BITS_IN_LONG + offset) );
}
find_set_next_zero( long *bank)
{
// bank is 32 bits BITS_IN_LONG
int offset = 0;
for ( offset = 0; offset < BITS_IN_LONG; offset++ )
{
if ( (*bank & ( 1L << offset)) = = 0L ) // find 0
// set 0 to to 1
*bank != (1L << offset );
// call a function to write new bank to file
update(bank);
return offset;
}
}
return BANK_FULL
}
Releasing the resource:
106742802
15
// find the bit in the bitmap corresponding to the resource.
// the resource ( bit position) is the only argument to the function
Long restorebit(long resource // bit position )
{
long bank, bank_no, bit, find_bank();
openbit();
// open file containing bit map
// fibd the correct group of 32 bits
// calculate bank number
bank_no = resource / BITS_IN_LONG;
// calculate the offset within the bank using modulous
// (remainder) operator
bit = resource % BITS_IN_LONG;
// the find_bank function returns the appropriate offset
// in the file and reads in the bank
bank_no = find_bank(bank_no, &bank );
// make sure resource was allocated
assert( bank & ( 1L MM bit ) );
// The bit is turned off by “anding” a mask into the
// bank. The mask (1L << bit ) is created using the offset to shift
// a 32 – bit representation of 1 to the left, and then taking its
// complement. All bits will be as before except for the
// target bit which will be set to zero.
bank &= ~(1L << bit );
// update the bitmap file and return the resource number released
update ( &bank);
return (resource);
}
106742802
16
Download