fig11_01.cpp (1 of 2)

Download Report

Transcript fig11_01.cpp (1 of 2)

1
Lecture Note 10 – Templates
and File Processing
Outline
Templates
Function Templates
Class Templates
File Processing
Sequential-Access File
Random-Access Files
2
Templates
• Templates
– Function templates
• Specify entire range of related (overloaded) functions
– Function-template specializations
– Class templates
• Specify entire range of related classes
– Class-template specializations
3
Function Templates
• Overloaded functions
– Similar operations
• Different types of data
• Function templates
– Identical operations
• Different types of data
– Single function template
• Compiler generates separate object-code functions
– Type checking
4
Function Templates
• Function-template definitions
– Keyword template
– List formal type parameters in angle brackets (< and >)
• Each parameter preceded by keyword class or typename
– class and typename interchangeable
template< class T >
template< typename ElementType >
• Specify types of
– Arguments to function
– Return type of function
– Variables within function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
5
// Fig. 11.1: fig11_01.cpp
// Using template functions.
#include <iostream>
using std::cout;
using std::endl;
Function template definition;
declare single formal type
parameter T.
// function template printArray definition
template< class T >
void printArray( const T *array, const int count )
{
for ( int i = 0; i < count; i++ ) T is type parameter;
cout << array[ i ] << " ";
valid identifier.
cout << endl;
} // end function printArray
int main()
{
const int aCount = 5;
const int bCount = 7;
const int cCount = 6;
use any
If T is user-defined type,
stream-insertion operator
must be overloaded for class
T.
fig11_01.cpp
(1 of 2)
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
6
int a[ aCount ] = { 1, 2, 3, 4, 5 };
double b[ bCount ] = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 };
char c[ cCount ] = "HELLO"; // 6th position for null
fig11_01.cpp
(2 of 2)
cout << "Array a contains:" << endl;
// call integer function-template specialization
Creates complete
printArray( a, aCount );
function-template specialization for printing
array of ints:
cout << "Array b contains:" << endl;
void printArray( const int *array, const int count )
{
// call double function-template specialization
for ( int i = 0; i < count; i++ )
printArray( b, bCount );
cout << array[ i ] << " "
cout << endl;
cout << "Array c contains:" << endl; } // end function printArray
// call character function-template specialization
printArray( c, cCount );
return 0;
} // end main
Array a
1 2 3 4
Array b
1.1 2.2
Array c
H E L L
contains:
5
contains:
3.3 4.4 5.5 6.6 7.7
contains:
O
Compiler infers T is
double; instantiates
function-template
specialization where T is
double.
Compiler infers T is char;
instantiates function-template
specialization where T is
char.
fig11_01.cpp
output (1 of 1)
#include <iostream.h>
//Tplate2.cpp
#define max 5
template <class Tpt>
Tpt SumArray(const Tpt a[], int )
{
int i;
Tpt sum;
sum = a[0];
for( i=1; i < max; i++)
sum = sum + a[i];
return sum;
}
int main(void)
{
char screenoff;
int a[max] = {1,2,3,4,5};
float b[max]= {1.1, 2.2, 3.3, 4.4, 5.5};
cout << "Number sum : " << SumArray(a, max) << endl;
cout << "Number sum : " << SumArray(b, max) << endl;
cin >> screenoff;
}
7
8
Class Templates
• Stack
– LIFO (last-in-first-out) structure
• Class templates
– Generic programming
– Describe notion of stack generically
• Instantiate type-specific version
– Parameterized types
• Require one or more type parameters
– Customize “generic class” template to form class-template
specialization
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
9
// Fig. 11.2: tstack1.h
// Stack class template.
#ifndef TSTACK1_H
#define TSTACK1_H
Specify class-template
definition; type parameter T
indicates type of Stack class
to be created.
template< class T >
class Stack {
public:
Stack( int = 10 );
// default constructor (stack size 10)
// destructor
~Stack()
{
delete [] stackPtr;
} // end ~Stack destructor
bool push( const T& );
bool pop( T& );
// push an element onto the stack
// pop an element off the stack
// determine whether Stack is empty
bool isEmpty() const
Function
{
T.
return top == -1;
} // end function isEmpty
parameters of type
tstack1.h (1 of 3)
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// determine whether Stack is full
bool isFull() const
{
return top == size - 1;
} // end function isFull
private:
int size;
int top;
T *stackPtr;
10
tstack1.h (2 of 3)
Array of elements of type T.
// # of elements in the stack
// location of the top element
// pointer to the stack
}; // end class Stack
Member functions preceded
with header
template< class T >
// constructor
Use binary scope resolution
template< class T >
operator (::) with classStack< T >::Stack( int s )
template name (Stack< T
{
to tie definition to class
size = s > 0 ? s : 10;
template’s scope.
top = -1; // Stack initially empty
stackPtr = new T[ size ]; // allocate memory for elements
>)
} // end Stack constructor
Constructor creates array of type T.
For example, compiler generates
// push element onto stack;
// if successful, return true; otherwise, return false
stackPtr = new T[ size ];
for class-template specialization
Stack< double >.
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
template< class T >
bool Stack< T >::push( const T &pushValue )
{
if ( !isFull() ) {
stackPtr[ ++top ] = pushValue; // place item on Stack
return true; // push successful
} // end if
return false;
// push unsuccessful
} // end function push
// pop element off stack;
// if successful, return true; otherwise, return false
template< class T >
bool Stack< T >::pop( T &popValue )
{
if ( !isEmpty() ) {
popValue = stackPtr[ top-- ]; // remove item from Stack
return true; // pop successful
} // end if
return false;
// pop unsuccessful
} // end function pop
#endif
11
Member functions preceded
with header
template< class T >
Use binary scope resolution
operator (::) with classtemplate name (Stack< T >)
to tie definition to class
template’s scope.
tstack1.h (3 of 3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
12
// Fig. 11.3: fig11_03.cpp
// Stack-class-template test program.
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
#include "tstack1.h"
Link to class template
definition.
fig11_03.cpp
(1 of 2)
// Stack class template definition
int main()
{
Stack< double > doubleStack( 5 );
double doubleValue = 1.1;
cout << "Pushing elements onto doubleStack\n";
while ( doubleStack.push( doubleValue ) ) {
cout << doubleValue << ' ';
doubleValue += 1.1;
Instantiate object of class
Stack< double >.
Invoke function push of
class-template specialization
Stack< double >.
} // end while
cout << "\nStack is full. Cannot push " << doubleValue
<< "\n\nPopping elements from doubleStack\n";
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
13
fig11_03.cpp
(2 of 2)
while ( doubleStack.pop( doubleValue ) )
cout << doubleValue << ' ';
cout << "\nStack is empty. Cannot pop\n";
Stack< int > intStack;
int intValue = 1;
cout << "\nPushing elements onto intStack\n";
Invoke function pop of classtemplate specialization
Stack< double >.
while ( intStack.push( intValue ) ) {
cout << intValue << ' ';
++intValue;
} // end while
cout << "\nStack is full. Cannot push " << intValue
<< "\n\nPopping elements from intStack\n";
while ( intStack.pop( intValue ) )
cout << intValue << ' ';
cout << "\nStack is empty. Cannot pop\n";
Note similarity of code for
Stack< int > to code for
Stack< double >.
Pushing elements onto doubleStack
1.1 2.2 3.3 4.4 5.5
Stack is full. Cannot push 6.6
Popping elements from doubleStack
5.5 4.4 3.3 2.2 1.1
Stack is empty. Cannot pop
Pushing elements onto intStack
1 2 3 4 5 6 7 8 9 10
Stack is full. Cannot push 11
return 0;
} // end main
Popping elements from intStack
10 9 8 7 6 5 4 3 2 1
Stack is empty. Cannot pop
14
Class Templates and Nontype Parameters
• Class templates
– Nontype parameters
• Default arguments
• Treated as consts
• Example:
template< class T, int elements >
Stack< double, 100 > mostRecentSalesFigures;
– Declares object of type Stack< double, 100>
15
File Processing
• Storage of data
– Arrays, variables are temporary
– Files are permanent
• Magnetic disk, optical disk, tapes
• File processing
– Create, update, process files
– Sequential and random access
16
The Data Hierarchy
• From smallest to largest
– Bit (binary digit)
•
•
•
•
1 or 0
Everything in computer ultimately represented as bits
Cumbersome for humans to use
Character set
– Digits, letters, symbols used to represent data
– Every character represented by 1's and 0's
– Byte: 8 bits
• Can store a character (char)
• Also Unicode for large character sets (wchar_t)
17
The Data Hierarchy
• From smallest to largest (continued)
– Field: group of characters with some meaning
• Your name
– Record: group of related fields
• struct or class in C++
• In payroll system, could be name, SS#, address, wage
• Each field associated with same employee
• Record key: field used to uniquely identify record
– File: group of related records
• Payroll for entire company
• Sequential file: records stored by key
– Database: group of related files
• Payroll, accounts-receivable, inventory…
18
The Data Hierarchy
Sally
Judy
Judy
01001010
1
Bit
Black
Tom
Blue
Judy
Green
Iris
Orange
Randy
Red
Green
Field
Byte (ASCII character J)
File
Record
19
Files and Streams
• C++ views file as sequence of bytes
– Ends with end-of-file marker
0
1
2
3
4
5
6
7
8
9
...
...
n-1
end-of-file marker
• When file opened
– Object created, stream associated with it
– cin, cout, etc. created when <iostream> included
• Communication between program and file/device
20
Files and Streams
• To perform file processing
– Include <iostream> and <fstream>
– Class templates
• basic_ifstream (input)
• basic_ofstream (output)
• basic_fstream (I/O)
– typedefs for specializations that allow char I/O
• ifstream (char input)
• ofstream (char output)
• fstream (char I/O)
21
Files and Streams
• Opening files
– Create objects from template
– Derive from stream classes
• Can use stream methods from Ch. 12
• put, get, peek, etc.
basic_ios
basic_istream
basic_ifstream
basic_ostream
basic_iostream
basic_fstream
basic_ofstream
22
Creating a Sequential-Access File
• C++ imposes no structure on file
– Concept of "record" must be implemented by programmer
• To open file, create objects
– Creates "line of communication" from object to file
– Classes
• ifstream (input only)
• ofstream (output only)
• fstream (I/O)
– Constructors take file name and file-open mode
ofstream outClientFile( "filename", fileOpenMode );
– To attach a file later
Ofstream outClientFile;
outClientFile.open( "filename", fileOpenMode);
23
Creating a Sequential-Access File
• File-open modes
Mode
Description
ios::app
Write all output to the end of the file.
ios::ate
Open a file for output and move to the end of the
file (normally used to append data to a file).
Data can be written anywhere in the file.
Open a file for input.
Open a file for output.
Discard the file’s contents if it exists (this is
also the default action for ios::out)
ios::in
ios::out
ios::trunc
ios::binary
Open a file for binary (i.e., non-text) input or
output.
– ofstream opened for output by default
• ofstream outClientFile( "clients.dat", ios::out );
• ofstream outClientFile( "clients.dat");
24
Creating a Sequential-Access File
• Operations
– Overloaded operator!
• !outClientFile
• Returns nonzero (true) if badbit or failbit set
– Opened non-existent file for reading, wrong permissions
– Overloaded operator void*
• Converts stream object to pointer
• 0 when when failbit or badbit set, otherwise nonzero
– failbit set when EOF found
• while ( cin >> myVariable )
– Implicitly converts cin to pointer
– Loops until EOF
25
Creating a Sequential-Access File
• Operations
– Writing to file (just like cout)
• outClientFile << myVariable
– Closing file
• outClientFile.close()
• Automatically closed when destructor called
26
// basic file operations
#include <iostream>
#include <fstream>
[file example.txt]
using namespace std;
Writing this to a file
int main ()
{
ofstream myfile;
myfile.open ("example.txt");
myfile << "Writing this to a file.\n";
myfile.close();
return 0;
}
27
// writing on a text file
#include <iostream>
#include <fstream>
using namespace std;
[file example.txt]
This is a line.
This is another line.
int main ()
{
// ofstream myfile ("example.txt");
ofstream myfile;
myfile.open ("example.txt");
if (myfile.is_open())
{
myfile << "This is a line.\n";
myfile << "This is another line.\n";
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Fig. 14.4: fig14_04.cpp
// Create a sequential file.
#include <iostream>
using
using
using
using
using
fig14_04.cpp
(1 of 2)
std::cout;
std::cin;
std::ios;
std::cerr;
std::endl;
#include <fstream>
using std::ofstream;
#include <cstdlib>
Notice the the header files
required for file I/O.
// exit prototype
int main()
{
// ofstream constructor opens file
ofstream outClientFile( "clients.dat", ios::out );
// exit program if unable to create file
if ( !outClientFile ) { // overloaded ! operator
cerr << "File could not be opened" << endl;
exit( 1 );
} // end if
ofstream object created
and used to open file
"clients.dat". If the file
does not exist, it is created.
! operator used to test if the
file opened properly.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
29
cout << "Enter the account, name, and balance." << endl
<< "Enter end-of-file to end input.\n? ";
cin is implicitly converted to
a pointer. When EOF is
encountered, it returns 0 and
the loop stops.
int account;
char name[ 30 ];
double balance;
// read account, name and balance from cin, then place in file
while ( cin >> account >> name >> balance ) {
outClientFile << account << ' ' << name << ' ' << balance
<< endl;
cout << "? ";
} // end while
return 0;
Write data to file like a
regular stream.
// ofstream destructor closes file
} // end main
Enter
Enter
? 100
? 200
? 300
? 400
? 500
? ^Z
fig14_04.cpp
(2 of 2)
the account, name, and balance.
end-of-file to end input.
Jones 24.98
Doe 345.67
White 0.00
Stone -42.16
Rich 224.62
File closed when destructor
called for object. Can be
explicitly closed with
close().
fig14_04.cpp
output (1 of 1)
30
Reading Data from a Sequential-Access File
• Reading files
– ifstream inClientFile( "filename", ios::in );
– Overloaded !
• !inClientFile tests if file was opened properly
– operator void* converts to pointer
• while (inClientFile >> myVariable)
• Stops when EOF found (gets value 0)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
31
// Fig. 14.7: fig14_07.cpp
// Reading and printing a sequential file.
#include <iostream>
using
using
using
using
using
using
using
using
using
std::cout;
std::cin;
std::ios;
std::cerr;
std::endl;
std::left;
std::right;
std::fixed;
std::showpoint;
#include <fstream>
using std::ifstream;
#include <iomanip>
using std::setw;
using std::setprecision;
#include <cstdlib> // exit prototype
void outputLine( int, const char * const, double );
fig14_07.cpp
(1 of 3)
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
int main()
{
// ifstream constructor opens the file
ifstream inClientFile( "clients.dat", ios::in );
32
Open and test file for input.
// exit program if ifstream could not open file
if ( !inClientFile ) {
cerr << "File could not be opened" << endl;
exit( 1 );
fig14_07.cpp
(2 of 3)
} // end if
int account;
char name[ 30 ];
double balance;
cout << left << setw( 10 ) << "Account" << setw( 13 )
<< "Name" << "Balance" << endl << fixed << showpoint;
// display each record in file
while ( inClientFile >> account >> name >> balance )
outputLine( account, name, balance );
return 0; // ifstream destructor closes the file
} // end main
Read from file until EOF
found.
54
55
56
57
58
59
60
61
62
63
33
// display single record from file
void outputLine( int account, const char * const name,
double balance )
{
cout << left << setw( 10 ) << account << setw( 13 ) << name
<< setw( 7 ) << setprecision( 2 ) << right << balance
<< endl;
fig14_07.cpp
(3 of 3)
} // end function outputLine
Account
100
200
300
400
500
Name
Jones
Doe
White
Stone
Rich
Balance
24.98
345.67
0.00
-42.16
224.62
fig14_07.cpp
output (1 of 1)
34
Updating Sequential-Access Files
• Updating sequential files
– Risk overwriting other data
– Example: change name "White" to "Worthington"
• Old data
300 White 0.00 400 Jones 32.87
• Insert new data
300 Worthington 0.00
300 White 0.00 400 Jones 32.87
Data gets overwritten
300 Worthington 0.00ones 32.87
– Formatted text different from internal representation
– Problem can be avoided, but awkward
35
Reading Data from a Sequential-Access File
• File position pointers
– Number of next byte to read/write
– Functions to reposition pointer
• seekg (seek get for istream class)
• seekp (seek put for ostream class)
– seekg and seekp take offset and direction
• Offset: number of bytes relative to direction
• Direction (ios::beg default)
– ios::beg - relative to beginning of stream
– ios::cur - relative to current position
– ios::end - relative to end
36
Reading Data from a Sequential-Access File
• Examples
– fileObject.seekg(0)
• Goes to front of file (location 0) because ios::beg is default
– fileObject.seekg(n)
• Goes to nth byte from beginning
– fileObject.seekg(n, ios::cur)
• Goes n bytes forward
– fileObject.seekg(y, ios::end)
• Goes y bytes back from end
– fileObject.seekg(0, ios::cur)
• Goes to last byte
– seekp similar
37
Reading Data from a Sequential-Access File
• To find pointer location
– tellg and tellp
– location = fileObject.tellg()
• Upcoming example
38
#include "stdafx.h"
// obtaining file size
#include <iostream>
#include <fstream>
using namespace std;
int main () {
long begin,end;
ifstream myfile ("example.txt");
begin = myfile.tellg();
myfile.seekg (0, ios::end);
end = myfile.tellg();
myfile.close();
cout << "size is: " << (end-begin) << " bytes.\n";
return 0;
}
[file example.txt]
This is a line.
This is another line.
size is: 40 bytes.
Slide 27 output
39
#include <fstream.h> //Direct1.cpp
#include <iostream.h>
int main ()
{
char c, letters[7] = {'a','b','c','d','e','f','g'};
fstream fp; // pointer to file
fp.open("datafile.dat", ios::out | ios::in);
if (!fp.good())
{
cout << "ERROR: cannot create file ";
return 1;
}
cout << "Open data file\n";
for (int i = 0; i <= 6; i++)
{
fp.seekg(i * sizeof(char), ios::beg); //pointer location
fp << letters[i];
// write here
cout << "Write " << letters[i] << " at position " << i << endl;
}
fp.seekg(6 * sizeof(char), ios::beg);
fp >> c;
cout << "\nRead " << c << " at position 6\n";
[file datafile.dat]
abcdefg
fp.seekg(0 * sizeof(char), ios::beg);
fp >> c;
cout << "Read " << c << " at position 0\n";
fp.close();
return 0;
}
40
Random-Access Files
• Instant access
– Want to locate record quickly
• Airline reservations, ATMs
– Sequential files must search through each one
• Random-access files are solution
– Instant access
– Insert record without destroying other data
– Update/delete items without changing other data
41
Random-Access Files
• C++ imposes no structure on files
– Programmer must create random-access files
– Simplest way: fixed-length records
• Calculate position in file from record size and key
0
100
200
300
400
500
}
byte offsets
}
}
}
}
}
}
100
100
100
100
100
100
bytes
bytes
bytes
bytes
bytes
bytes
42
Creating a Random-Access File
• "1234567" (char *) vs 1234567 (int)
– char * takes 8 bytes (1 for each character + null)
– int takes fixed number of bytes (perhaps 4)
• 123 same size in bytes as 1234567
• << operator and write()
– outFile << number
• Outputs number (int) as a char *
• Variable number of bytes
– outFile.write( const char *, size );
• Outputs raw bytes
• Takes pointer to memory location, number of bytes to write
– Copies data directly from memory into file
– Does not convert to char *
43
Creating a Random-Access File
• Example
outFile.write( reinterpret_cast<const char *>(&number),
sizeof( number ) );
– &number is an int *
• Convert to const char * with reinterpret_cast
– sizeof(number)
• Size of number (an int) in bytes
– read function similar (more later)
– Must use write/read between compatible machines
• Only when using raw, unformatted data
– Use ios::binary for raw writes/reads
44
Creating a Random-Access File
• Usually write entire struct or object to file
Example:
Example consists of a file creation datafile.dat and a random reading of
file records that were created from the structure
Example does not provide all facilities to read, write, update and delete
records it does provide enough information to develop such a system
Record access is by number although easily modifiable to relate say
part number to record etc
45
#include <fstream.h> //Direct2.cpp
#include <iostream.h>
int main ()
{
char screenoff;
struct Scar_parts
{
int part_no;
char name[20];
int number_of;
};
Scar_parts Rover_parts;
fstream fp; // pointer to file
ofstream cars("datafile.dat", ios::out | ios::in | ios::binary);
if (!cars)
{
cout << "ERROR: cannot create file ";
return 1;
}
46
cout << "Open data file\n";
cout << "Input part number, Part name, Number sent\n";
Rover_parts.part_no = 0;
while(Rover_parts.part_no < 5) {
cin >> Rover_parts.part_no >> Rover_parts.name >> Rover_parts.number_of;
fp.seekg(Rover_parts.part_no * sizeof(Scar_parts));
cars.write(reinterpret_cast<const char*> (&Rover_parts), sizeof(Scar_parts));
}
cars.close();
fp.open("datafile.dat", ios::in | ios::binary | ios::beg);
cout << "Output part number, Part name, Number sent\n";
fp.seekg(0 * sizeof(Scar_parts), ios::beg);
fp.read((char*) &Rover_parts, sizeof(Scar_parts));
cout << Rover_parts.number_of << Rover_parts.name << Rover_parts.part_no ;
cout << "\nSecond record\n";
fp.seekg(2 * sizeof(Scar_parts), ios::beg);
fp.read((char*) &Rover_parts, sizeof(Scar_parts));
cout << Rover_parts.number_of << Rover_parts.name << Rover_parts.part_no ;
cin >> screenoff;
}
47
Lecture Note 10 – Templates
and File Processing
Summary
Templates
Function Templates
Class Templates
File Processing
Sequential-Access File
Random-Access Files
48
Example_Creating a Random-Access File
Problem statement
– Credit processing program
– Store at most 100 fixed-length records
– Record
• Account number (key)
• First and last name
• Balance
– Account operations
• Update, create new, delete, list all accounts in a file
• Next: program to create blank 100-record file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Fig. 14.10: clientData.h
// Class ClientData definition used in Fig. 14.12–Fig. 14.15.
#ifndef CLIENTDATA_H
#define CLIENTDATA_H
#include <iostream>
using std::string;
Class ClientData stores
the information for each
person. 100 blank
ClientData objects will be
written to a file.
class ClientData {
public:
// default ClientData constructor
ClientData( int = 0, string = "", string = "", double = 0.0 );
// accessor functions for accountNumber
void setAccountNumber( int );
int getAccountNumber() const;
// accessor functions for lastName
void setLastName( string );
string getLastName() const;
49
clientData.h
(1 of 2)
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
50
// accessor functions for firstName
void setFirstName( string );
string getFirstName() const;
clientData.h
(2 of 2)
// accessor functions for balance
void setBalance( double );
double getBalance() const;
private:
int accountNumber;
char lastName[ 15 ];
char firstName[ 10 ];
double balance;
}; // end class ClientData
#endif
Put limits on the size of the
first and last name.
accountNumber (an int)
and balance (double) are
already of a fixed size.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
51
// Fig. 14.11: ClientData.cpp
// Class ClientData stores customer's credit information.
#include <iostream>
using std::string;
#include <cstring>
#include "clientData.h"
// default ClientData constructor
ClientData::ClientData( int accountNumberValue,
string lastNameValue, string firstNameValue,
double balanceValue )
{
setAccountNumber( accountNumberValue );
setLastName( lastNameValue );
setFirstName( firstNameValue );
setBalance( balanceValue );
} // end ClientData constructor
// get account-number value
int ClientData::getAccountNumber() const
{
return accountNumber;
} // end function getAccountNumber
ClientData.cpp
(1 of 4)
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
52
// set account-number value
void ClientData::setAccountNumber( int accountNumberValue )
{
accountNumber = accountNumberValue;
} // end function setAccountNumber
// get last-name value
string ClientData::getLastName() const
{
return lastName;
} // end function getLastName
// set last-name value
void ClientData::setLastName( string lastNameString )
{
// copy at most 15 characters from string to lastName
const char *lastNameValue = lastNameString.data();
int length = strlen( lastNameValue );
length = ( length < 15 ? length : 14 );
strncpy( lastName, lastNameValue, length );
// append null character to lastName
lastName[ length ] = '\0';
ClientData.cpp
(2 of 4)
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
53
} // end function setLastName
// get first-name value
string ClientData::getFirstName() const
{
return firstName;
} // end function getFirstName
// set first-name value
void ClientData::setFirstName( string firstNameString )
{
// copy at most 10 characters from string to firstName
const char *firstNameValue = firstNameString.data();
int length = strlen( firstNameValue );
length = ( length < 10 ? length : 9 );
strncpy( firstName, firstNameValue, length );
// append new-line character to firstName
firstName[ length ] = '\0';
} // end function setFirstName
ClientData.cpp
(3 of 4)
78
79
80
81
82
83
84
85
86
87
88
89
90
// get balance value
double ClientData::getBalance() const
{
return balance;
} // end function getBalance
// set balance value
void ClientData::setBalance( double balanceValue )
{
balance = balanceValue;
} // end function setBalance
54
ClientData.cpp
(4 of 4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
55
// Fig. 14.12: fig14_12.cpp
// Creating a randomly accessed file.
#include <iostream>
fig14_12.cpp
(1 of 2)
using std::cerr;
using std::endl;
using std::ios;
#include <fstream>
using std::ofstream;
#include <cstdlib>
#include "clientData.h"
// ClientData class definition
int main()
{
ofstream outCredit( "credit.dat", ios::binary );
// exit program if ofstream could not open file
if ( !outCredit ) {
cerr << "File could not be opened." << endl;
exit( 1 );
} // end if
Open a file for raw writing
using an ofstream object
and ios::binary.
26
27
28
29
30
31
32
33
34
35
36
37
38
56
// create ClientData with no information
ClientData blankClient;
Create a blank object. Use
write to output the raw data
fig14_12.cpp
to a file (passing a pointer to
(2 of 2)
the object and its size).
// output 100 blank records to file
for ( int i = 0; i < 100; i++ )
outCredit.write(
reinterpret_cast< const char * >( &blankClient ),
sizeof( ClientData ) );
return 0;
} // end main
57
Example_ Writing Data Randomly to a
Random-Access File
• Use seekp to write to exact location in file
– Where does the first record begin?
• Byte 0
– The second record?
• Byte 0 + sizeof(object)
– Any record?
• (Recordnum - 1) * sizeof(object)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
58
// Fig. 14.13: fig14_13.cpp
// Writing to a random access file.
#include <iostream>
using
using
using
using
using
fig14_13.cpp
(1 of 4)
std::cerr;
std::endl;
std::cout;
std::cin;
std::ios;
#include <iomanip>
using std::setw;
#include <fstream>
using std::ofstream;
#include <cstdlib>
#include "clientData.h"
// ClientData class definition
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
59
int main()
{
int accountNumber;
char lastName[ 15 ];
char firstName[ 10 ];
double balance;
Open file for raw (binary)
fig14_13.cpp
writing.
(2 of 4)
ofstream outCredit( "credit.dat", ios::binary );
// exit program if ofstream cannot open file
if ( !outCredit ) {
cerr << "File could not be opened." << endl;
exit( 1 );
} // end if
cout << "Enter account number "
<< "(1 to 100, 0 to end input)\n? ";
Get account number, put into
number
object. It has not yet been
written to file.
// require user to specify account
ClientData client;
cin >> accountNumber;
client.setAccountNumber( accountNumber );
46
47
48
49
50
51
52
53
54
56
57
58
59
61
62
63
65
66
67
68
70
71
72
73
75
77
78
60
// user enters information, which is copied into file
while ( client.getAccountNumber() > 0 &&
client.getAccountNumber() <= 100 ) {
// user enters last name, first name and balance
cout << "Enter lastname, firstname, balance\n? ";
cin >> setw( 15 ) >> lastName;
cin >> setw( 10 ) >> firstName;
cin >> balance;
// set record lastName, firstName and balance values
client.setLastName( lastName ); Position outCredit to the
client.setFirstName( firstName );
proper location in the file
client.setBalance( balance );
(based on the account
// seek position in file of user-specified record
number).
outCredit.seekp( ( client.getAccountNumber()
- 1 ) *
sizeof( ClientData ) );
// write user-specified information in file
Write ClientData object
outCredit.write(
to file
at specified
position.
reinterpret_cast< const char * >(
&client
),
sizeof( ClientData ) );
// enable user to specify another account number
cout << "Enter account number\n? ";
cin >> accountNumber;
client.setAccountNumber( accountNumber );
} // end while
return 0;
} // end main
fig14_13.cpp
(3 of 4)
Enter account number (1 to
? 37
Enter lastname, firstname,
? Barker Doug 0.00
Enter account number
? 29
Enter lastname, firstname,
? Brown Nancy -24.54
Enter account number
? 96
Enter lastname, firstname,
? Stone Sam 34.98
Enter account number
? 88
Enter lastname, firstname,
? Smith Dave 258.34
Enter account number
? 33
Enter lastname, firstname,
? Dunn Stacey 314.33
Enter account number
? 0
61
100, 0 to end input)
balance
Notice that accounts can be
created in any order.
balance
balance
balance
balance
fig14_13.cpp
output (1 of 1)
62
Example_ Reading Data Sequentially
from a Random-Access File
• read - similar to write
– Reads raw bytes from file into memory
– inFile.read( reinterpret_cast<char *>( &number ),
sizeof( int ) );
• &number: location to store data
• sizeof(int): how many bytes to read
– Do not use inFile >> number with raw bytes
• >> expects char *
• Upcoming program
– Output data from a random-access file
– Go through each record sequentially
• If no data (accountNumber == 0) then skip
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
63
// Fig. 14.14: fig14_14.cpp
// Reading a random access file.
#include <iostream>
using
using
using
using
using
using
using
using
std::cout;
std::endl;
std::ios;
std::cerr;
std::left;
std::right;
std::fixed;
std::showpoint;
#include <iomanip>
using std::setprecision;
using std::setw;
#include <fstream>
using std::ifstream;
using std::ostream;
#include <cstdlib> // exit protoyype
#include "clientData.h" // ClientData class definition
fig14_14.cpp
(1 of 3)
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
64
void outputLine( ostream&, const ClientData & );
int main()
{
ifstream inCredit( "credit.dat", ios::in );
fig14_14.cpp
(2 of 3)
// exit program if ifstream cannot open file
if ( !inCredit ) {
cerr << "File could not be opened." << endl;
exit( 1 );
Read
} // end if
sizeof(ClientData) bytes and put
into object client. This may be an empty
record.
cout << left << setw( 10 ) << "Account" << setw( 16 )
<< "Last Name" << setw( 11 ) << "First Name" << left
<< setw( 10 ) << right << "Balance" << endl;
ClientData client; // create record
// read first record from file
inCredit.read( reinterpret_cast< char * >( &client ),
sizeof( ClientData ) );
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
65
// read all records from file
while ( inCredit && !inCredit.eof() ) {
fig14_14.cpp
(3 of 3)
// display record
if ( client.getAccountNumber() != 0 )
outputLine( cout, client );
Loop exits if there is an error
reading (inCredit == 0)
or EOF is found
(inCredit.eof() == 1)
// read next from file
inCredit.read( reinterpret_cast< char * >( &client ),
sizeof( ClientData ) );
} // end while
return 0;
} // end main
Output non-empty accounts.
Note that outputLine
takes an ostream argument.
We could easily output to
another file (opened with an
ofstream object, which
derives from ostream).
// display single record
void outputLine( ostream &output, const ClientData &record )
{
output << left << setw( 10 ) << record.getAccountNumber()
<< setw( 16 ) << record.getLastName().data()
<< setw( 11 ) << record.getFirstName().data()
<< setw( 10 ) << setprecision( 2 ) << right << fixed
<< showpoint << record.getBalance() << endl;
} // end outputLine
Account
29
33
37
88
96
Last Name
Brown
Dunn
Barker
Smith
Stone
First Name
Nancy
Stacey
Doug
Dave
Sam
Balance
-24.54
314.33
0.00
258.34
34.98
66
fig14_14.cpp
output (1 of 1)