Download presentation
Presentation is loading. Please wait.
1
Chapter 15 Binary and Random Access Files
2
15.1 Text Files Versus Binary Files – Comparison
Readable by humans Translates information being written to the file into ASCII or Unicode characters Binary files Written in a way that requires no translation Virtually unreadable by humans Unusable for reports
3
15.1 Text Files Versus Binary Files – Hex Dump
Program executables or documents created using Microsoft Word or other word processors are examples of binary files Visual Studio actually shows a hex dump of binary files hex dump Shows contents of a binary file in hexadecimal format as well as a translation of those bytes recognizable as ASCII or Unicode characters
4
15.1.1 Advantages and Disadvantages of Binary Files
No need to translate into ASCII characters Allows special formatting symbols or commands to be placed within the file Disadvantages Not directly human readable Not always portable from one machine to another
5
15.2 Opening and Closing Binary Files – Syntax
Opening is similar as text files ifstream inFile ( filename, mode ); -- OR -- ofstream outFile; outFile.open ( filename, mode );
6
15.2 Opening and Closing Binary Files – Modes
Description ios::in Open file for input. ios::out Open file for output. ios::app Open file for output. All new output is added at the end of the file. ios::ate Open file with the file pointer initially set at the end of the file. Data can be written anywhere within the file. ios::binary Open file in binary mode (the default mode is text). ios::trunc Open file for output. If already exists, it is replaced by the new file. If using ios::out this is the default unless you specify ios::app, ios::ate, or ios::in.
7
15.2 Opening and Closing Binary Files – Examples
When working with binary streams, include the second parameter ios::binary ifstream input ( "filename.bin", ios::binary ); ofstream fout; fout.open ( "filename.bin", ios::out | ios::binary ); ofstream data ( "c:\\data.bin", ios::out | ios::app | ios::binary ); Multiple file mode flags can be combined using the bitwise OR operator (|) The binary file in the third example is opened in append mode Remember: Regardless of the mode, always check to make sure the file opened successfully before attempting to access it.
8
15.2 Opening and Closing Binary Files – Refresher
clear method clears, or resets, the I/O state flags for the stream When end of a file (EOF) is reached a stream state flag of eofbit is set Attempt to reuse a stream object requires clearing this flag Once done with input and output activities always close the file Syntax same as used when closing text files Style note Common when naming files to use extension of .bin as illustrated in our examples
9
15.3 Binary File I/O – Syntax
Reading Accomplished using an ifstream object stream.read ( char * buffer, streamsize size ); Writing Accomplished using an ofstream object stream.write ( char * buffer, streamsize size ); First parameter Information to be written, or buffer to store the information Must be cast to a char * (i.e., a character pointer) Requires an address of a block of memory where every element is one byte long Second parameter Number of bytes to be read or written If EOF marker is encountered before extracting the number of bytes specified, the read method will stop The gcount member function is used to retrieve the number of bytes read during the last read Note: streamsize equates to an signed integral data type Note: Reading a block of data at once in more efficient than one byte at a time. Also, cuts down the number of storage device accesses, thus speeding up I/O.
10
15.3 Binary File I/O – main Example
struct EMP { char name[30]; // Use cString not dynamic short int age; }; const short int NUM_EMPLOYEES = 3; int main ( ) EMP ray[NUM_EMPLOYEES]; FillArrayFromKeyboard ( ray ); WriteToFile ( ray ); ReadFromFile ( ray ); PrintArray ( ray ); return 0; }
11
15.3 Binary File I/O – WriteToFile Example
void WriteToFile ( EMP ray[] ) { ofstream fout ( "binary.bin", ios::out | ios::binary ); if ( fout.is_open ( ) ) fout.write ( reinterpret_cast <char *> (ray), sizeof ( EMP ) * NUM_EMPLOYEES ); fout.close ( ); } else cout << "File not opened" << endl;
12
15.3 Binary File I/O – ReadFromFile Example
void ReadFromFile ( EMP ray[] ) { ifstream fin ( "binary.bin", ios::in | ios::binary ); if ( fin.is_open ( ) ) fin.read ( reinterpret_cast <char *>(ray), sizeof ( EMP ) * NUM_EMPLOYEES ); cout << "Number of bytes read is: " << fin.gcount ( ); fin.close ( ); } else cout << "File not opened" << endl;
13
15.3 Binary File I/O – Explanation
The reinterpret_cast on the previous slide is another form of type casting usually used to convert an address to a different type of address Discouraged by many programmers because it can be unsafe, it is a necessary evil in this case Structure should contain only fixed size data members Do not use pointers as data members until after the next section
14
15.4 Record Serialization and Deserialization – Definition
Writing and reading the data that is a fixed size is relatively simple With dynamic cStrings it is not enough to write the data, it also must have information to be able to recreate the dynamic cString Serialization The process of converting a record into a stream of bytes to store the data into a file Its main purpose is to save the data in order to be able to recreate it when needed Deserialization Recreating the data from a stream of bytes
15
15.4 Record Serialization and Deserialization – Process
Write the number of characters in the dynamic cString Write the actual string data Deserialization Reads the number of characters in the cString Dynamically allocate memory of the correct size Read the data from the binary file It is also common practice to write the number of records as the first piece of data in the file
16
15.4.1 Serialization – Step 1 Write the number of records to the file
fout.write ( reinterpret_cast<char *>(&num_faculty), sizeof ( num_faculty ) ); The figure below is a hex dump from Visual Studio Highlighted is the data written in little-endian format Remember: The read and write member functions require an address as its first parameter. If the variable to be serialized is not an address, the address of operator must be used to retrieve the variable’s address.
17
Serialization – Step 2 Writing the number of characters in the dynamic cString // Get length of name including '\0' str_length = strlen( ray[i].name ) + 1; // Write out length of name fout.write( reinterpret_cast<char *>( &str_length ), sizeof( str_length ) );
18
15.4.1 Serialization – Step 3 Writing the faculty member name
// Write out the name string // (Note: we do not need a reinterpret cast) fout.write( ray[i].name, str_length );
19
Serialization – Step 4 Writing the number of characters in the department name // Get length of department including '\0' str_length = strlen( ray[i].department ) + 1; // Write out length of department fout.write( reinterpret_cast<char *>( &str_length ), sizeof( str_length ) );
20
15.4.1 Serialization – Step 5 Writing the department name
// Write out the department string fout.write( ray[i].department, str_length ); This entire process repeats for every record in your array
21
15.4.2 Deserialization Step 1 Step 2 Step 3
// First need to read how many elements in dynamic array and create ray fin.read( reinterpret_cast<char *>( &num_faculty ), sizeof( num_faculty ) ); ray = new Faculty[ num_faculty ]; Step 2 // Read in the length of name and create the memory fin.read(reinterpret_cast<char *>(&length), sizeof(length)); ray[i].name = new char[length]; // Now read in the name into the array fin.read(ray[i].name, length); Step 3 // Read in the length of department and create the memory fin.read( reinterpret_cast<char *>( &length ), sizeof( length ) ); ray[i].department = new char[length]; // Now read in the department into the array fin.read( ray[i].department, length );
22
15.4.3 Putting it all Together
We showed a lot of code snippets on the previous slides This is a great learning tool which shows our penchant for step-wise refinement However it is also helpful to see an entire working program This program is shown in Example of the book and can be downloaded from the website
23
15.5 Sequential Files vs. Random Access Files
Capability to directly access a specific location within a file Requires ability to move the File Position Marker (FPM) FPM is a term we use to indicate the current position within the file Stream objects have their own internal marker for referencing a position within a file ifstream Called the get pointer and points to the location of the data that will be read ofstream Called the put pointer and indicates location within the file where data will be written
24
15.5.1 Determining Current FPM Location
Two different member functions to determine where the pointer is currently located within a file pos_type stream.tellg( ); pos_type stream.tellp( ); Return type is a long integer value indicating the number of bytes the FPM is from the start of the file ifstream fin ( "c:\\temp\\students.bin", ios::in | ios::binary ); ... fin.read ( reinterpret_cast<char *>(student_array), sizeof ( STUDENT ) * 2 ); long int pointer_position = fin.tellg ( ); If sizeof the STUDENT structure is 56, value returned by tellg would be 112
25
15.5.2 Moving the FPM – seekg and seekp
Member functions seekg and seekp allow positioning the pointer to any location within the file Both seekp and seekg have multiple definitions stream.seekg( pos_type position ); stream.seekp( pos_type position ); stream.seekg( off_type offset, ios_base::seekdir direction ); stream.seekp( off_type offset, ios_base::seekdir direction );
26
15.5.2 Moving the FPM – Seek Function Parameters
Single parameter form of seekg and seekp positions the FPM so it is the specified number of bytes from beginning of the file The two parameter form of the seek functions, positions the FPM relative to a specified offset as shown below Direction Description ios::beg Seek (change the current read or write position) relative to the beginning of the file. ios::cur Seek relative to the current FPM position. ios::end Seek relative to the end of the file.
27
15.5.2 Moving the FPM – seekg Example and Explanation
fin.seekg ( sizeof( STUDENT ) * 2 ); fin.seekg ( 10, ios::cur ); First statement moves the FPM the size of two STUDENT structures from the beginning Second example sets file marker 10 bytes toward the end of the file relative to the stream’s current FPM
28
15.5.2 Moving the FPM – Opening a File in Mixed Mode
In the following example the fstream object is opened for both input and output fstream Parent of both ifstream and ofstream classes Much of the functionality of the children is derived from the parent Used fstream because of the default modes of the other two classes To accomplish both reading and writing to the same stream, we used fstream The code also illustrates how to re-write a record in the file without altering or rewriting the other records
29
15.5.2 Moving the FPM – fstream Example Part 1
void LocateAndModifyRecord ( ) { EMP temp; // Opening the stream for both input and output fstream empFile( "binary.bin", ios::in | ios::out | ios::binary | ios::ate ); if ( empFile.is_open ( ) ) // Move FPM to second record from the front empFile.seekp ( sizeof ( EMP ) * 1 ); cout << "\n* Currently at postion: " << empFile.tellp ( ); empFile.read ( reinterpret_cast <char *>(&temp), sizeof ( EMP ) ); cout << "\n* The name in the second record is: " << temp.name; cout << "\n* The age in the second record is: " << temp.age;
30
15.5.2 Moving the FPM – fstream Example Part 2
// Move FPM 0 bytes from beginning of the stream empFile.seekg ( 0, ios::beg ); strcpy ( temp.name, "Jamie" ); temp.age = 41; // Write updated data into current (first) position empFile.write ( reinterpret_cast <char *>(&temp), sizeof ( EMP ) ); empFile.close ( ); } else cout << "File not opened" << endl;
31
15.6.1 C The Differences – File Modes
Second parameter to fopen is a cString representing the file mode Only modes discussed so far were r, w, and a (read, write and append) Below are some additional modes Mode Explanation r+ Read and write. File must exist. w+ Read and write. Will create file if possible. Existing data is destroyed. a+ Read and append. Will create file if possible. Existing data is retained. All writing will be done at the end of the file.
32
15.6.1 C The Differences – File Modes Example
In addition to the random access modes listed on previous page, code below shows a “b” can be appended to any C file mode cString to allow access to binary files FILE * input; FILE * fout; FILE * data; input = fopen ( "filename.bin", "rb" ); fout = fopen ( "filename.bin", "w+b" ); data = fopen ( "c:\\data.bin", "ab" );
33
15.6.2 C The Differences – fread and fwrite
Functions fread and fwrite are C counterparts to read and write size_t fread ( const void * buffer, size_t item_size, size_t num_items, FILE * fptr); size_t fwrite ( const void * buffer, size_t item_size, size_t num_items, FILE * fptr); Both functions require an address of the buffer in which the information is stored or will be stored This address will not need to be type cast because the function accepts a void *, a pointer to anything Second parameter is the size of one item Third parameter is the number of items to be written or read Last parameter is the C file pointer Both functions return the number of items, not bytes, completely read or written Remember: The size_t data type equates to an unsigned int.
34
15.6.2 C The Differences – main Example
typedef struct { char name[30]; short int age; } EMP; #define NUM_EMPLOYEES 3 ... int main ( ) EMP ray[NUM_EMPLOYEES]; FillArrayFromKeyboard ( ray ); WriteToFile ( ray ); ReadFromFile ( ray ); PrintArray ( ray ); return 0; }
35
15.6.2 C The Differences – WriteToFile Example
void WriteToFile ( EMP ray[] ) { FILE * fout; fout = fopen ( "binary.bin", "wb" ); if ( fout != NULL ) fwrite ( ray, sizeof ( EMP ), NUM_EMPLOYEES, fout ); fclose ( fout ); } else printf ( "File not opened\n" );
36
15.6.2 C The Differences – ReadFromFile Example
void ReadFromFile ( EMP ray[] ) { size_t num_items = 0; FILE * fin; fin = fopen ( "binary.bin", "rb" ); if ( fin != NULL ) num_items = fread ( ray, sizeof ( EMP ), NUM_EMPLOYEES, fin ); fclose ( fin ); printf ( "Number of bytes read is: %d", num_items ); } else printf ( "File not opened\n" );
37
15.6.3 C The Differences – Random Access Functions
Three C functions used to manipulate the FPM within binary files void rewind( FILE * stream ); long ftell( FILE * stream ); int fseek( FILE * stream, long offset, int origin ); The rewind function moves the FPM back to the beginning of the file ftell returns number of bytes the FPM is currently from the beginning of the file fseek repositions the FPM within the file
38
15.6.3 C The Differences – Origin Parameter
The origin parameter of fseek can have one of three values as shown below Identifier Description SEEK_CUR Position FPM relative to the current position. SEEK_END Position FPM relative to the end of the file. SEEK_SET Position FPM relative to the beginning the file.
39
15.6.3 C The Differences – Example Part 1
void LocateAndModifyRecord ( ) { EMP temp; // Opening the stream for both input and output FILE * empFile = fopen ( "binary.bin", "r+b" ); if ( empFile != NULL ) // Move to the beginning of the file rewind ( empFile ); // Move FPM to second record from the front fseek ( empFile, sizeof ( EMP ), SEEK_SET ); printf ( "\n* Currently at postion: %ld", ftell ( empFile ) ); fread ( &temp, sizeof ( EMP ), 1, empFile ); printf ( "\n* The name in the second record is: %s", temp.name ); printf ( "\n* The age in the second record is: %d", temp.age );
40
15.6.3 C The Differences – Example Part 2
// Move FPM 0 bytes from beginning of the stream fseek ( empFile, 0, SEEK_SET ); strcpy ( temp.name, "Jamie" ); temp.age = 41; // Write updated data into current (first) position fwrite ( &temp, sizeof ( EMP ), 1, empFile ); fclose ( empFile ); } else printf ( "File not opened" );
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.