Thread: Help with binary file c++

  1. #1
    Registered User
    Join Date
    May 2009
    Posts
    2

    Help with binary file c++

    Ok what i'm trying to do in this program is first create an empty binary file of size 31 records. Records includes studid & gpa. and then I insert valid record into the binary file with h(k) = key% 29..and then read this binary file sequentially and write the records and their position into output file.....

    sample input file
    31 2.34
    62 1.55
    60
    3.25
    333 3.33
    38 3.90
    -1 //read upto -1


    Code:
    studBinaryFile.h
    
    #include <iostream>
    #include <fstream>
    #include <iomanip>
    
    using namespace std;
    
    const int MIN_ID = 11;
    const int MAX_ID = 99;
    const float MIN_GPA = 0.00;
    const float MAX_GPA = 4.00;
    
    class StudBinaryFile
    {
     public:
    
     void setId(int idVal);
     
     void setGpa(float gpaVal);
    
     void ReadRd(int i,ifstream& inFile);
    
     bool validRd();
     
     void writeBinary(StudBinaryFile rd, ofstream& outFile);
    
     void writeInvalidRd(ofstream& outFile2);
    
     void readBinary(StudBinaryFile rd, ifstream& inFile, ofstream&    outFile2);
     
     void printData(int count, const StudBinaryFile& record, ofstream&  outFile2);
     
    private:
       int id;
       float gpa;
    };
    Code:
    studBinaryFile.cxx
    
    #include "studBinaryFile.h"
    
    void StudBinaryFile::setId(int idVal)
    {
    	id = idVal;
    }
    
    void StudBinaryFile::setGpa(float gpaVal)
    {
    	gpa = gpaVal;
    }
    
    void StudBinaryFile::ReadRd(int i, ifstream& inFile)
    {
    	id = i;
    	inFile >> gpa;
    }
    
    
    bool StudBinaryFile::validRd() 
    {
    	 return ((id >= MIN_ID)&&
                    (id <= MAX_ID)&&
                    (gpa >= MIN_GPA)&&
                    (gpa <= MAX_GPA));
    
    }
    
    void StudBinaryFile::writeBinary(StudBinaryFile rd, ofstream& outFile)
    {
    	outFile.seekp((id % 29) * sizeof(rd));
    	{outFile.write(reinterpret_cast<const char *> (&rd), sizeof(rd));}
    }
    
    void StudBinaryFile::readBinary(StudBinaryFile rd, ifstream& inFile, ofstream& outFile2)
    {
    	int count = 0;
    	inFile.read(reinterpret_cast<char *> (&rd), sizeof(StudBinaryFile));
    	while(inFile)
    	{
    		if (id != 0)
    		{
    			printData(count, rd, outFile2);
    			count++;
    		}
    		inFile.read(reinterpret_cast<char *> (&rd), sizeof(StudBinaryFile));		
    	}
    } 
    
    void StudBinaryFile::writeInvalidRd(ofstream& outFile2)
    {
    	outFile2 << id << setw(12) << gpa << endl;
    }
    
    void StudBinaryFile::printData(int count, const StudBinaryFile& record, ofstream& outFile2)
    {
    	if(record.id != 0)
    		outFile2 << count << ".)  "  << record.id << setw(12) << record.gpa << endl;
    	else
    		outFile2 << count << ".)  " << "Empty record" << endl;
    
    	count++;
    }
    Code:
    run.cxx
    
    #include "studBinaryFile.h"
    int main()
    {
    	ifstream inFile, inFile2;
    	ofstream outFile, outFile2;
    	inFile.open("in.data");
    	outFile.open("binrecords.bin",ios::out | ios::binary);
    
    	outFile2.open("out.data");
    
    	StudBinaryFile blankRd;
    	for (int i = 1; i<=31; i++)
    	{
    		blankRd.setId(0);
    		blankRd.setGpa(0.0);
    		outFile.write(reinterpret_cast<const char *> (&blankRd), sizeof(blankRd));
    	}
    
    	StudBinaryFile rd;
    	outFile.seekp(0L,ios::beg);
    	int spliter;
    	outFile2 << "*< Invalid Records Report >*" << endl;
    	
    	inFile >> spliter;
    	while(spliter != -1)
    	{
    		rd.ReadRd(spliter,inFile);
    		if(rd.validRd())
    		{
    			
    			rd.writeBinary(rd, outFile);
    		}
    		else
    			{rd.writeInvalidRd(outFile2);}
    		inFile >> spliter;
    	}
    	outFile2 << "<* end >*" << endl << endl;
    	inFile.close();
    	outFile.close();
    
    	outFile2 << "Reading random file sequentially" << endl;
    	inFile.open("binrecords.bin", ios::in | ios::binary);
    	rd.readBinary(rd, inFile, outFile2);
    
    	inFile.close();
    	return 0;
    }
    This is the output im getting
    Code:
    *< Invalid Records Report >*
    333        3.33
    <* end >*
    
    Reading random file sequentially
    0.)  Empty record
    1.)  Empty record
    2.)  60        3.25
    3.)  Empty record
    4.)  62        1.55
    5.)  Empty record
    6.)  Empty record
    7.)  Empty record
    8.)  Empty record
    9.)  38         3.9
    10.)  Empty record
    11.)  Empty record
    12.)  Empty record
    13.)  Empty record
    14.)  Empty record
    15.)  Empty record
    16.)  Empty record
    17.)  Empty record
    18.)  Empty record
    19.)  Empty record
    20.)  Empty record
    21.)  Empty record
    22.)  Empty record
    23.)  Empty record
    24.)  Empty record
    25.)  Empty record
    26.)  Empty record
    27.)  Empty record
    28.)  Empty record
    29.)  Empty record
    30.)  Empty record
    This is the output i want
    Code:
    *< Invalid Records Report >*
    333        3.33
    <* end >*
    
    Reading random file sequentially
    0.)  Empty record
    1.)  Empty record
    2.)  31        2.34
    3.)  60        3.25
    4.)  62        1.55
    5.)  Empty record
    6.)  Empty record
    7.)  Empty record
    8.)  Empty record
    9.)  38         3.9
    10.)  Empty record
    11.)  Empty record
    12.)  Empty record
    13.)  Empty record
    14.)  Empty record
    15.)  Empty record
    16.)  Empty record
    17.)  Empty record
    18.)  Empty record
    19.)  Empty record
    20.)  Empty record
    21.)  Empty record
    22.)  Empty record
    23.)  Empty record
    24.)  Empty record
    25.)  Empty record
    26.)  Empty record
    27.)  Empty record
    28.)  Empty record
    29.)  Empty record
    30.)  Empty record
    This program works fine except that its overriding some of the record because of collision problem ..someone please help me here

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Well, when I change one of your functions to look like this,
    Code:
    void StudBinaryFile::writeBinary(StudBinaryFile rd, ofstream& outFile)
    {
            std::cout << "Writing " << rd.get_id() << "," << rd.get_gpa()
                << " to " << (id % 29) << std::endl;
    	outFile.seekp((id % 29) * sizeof(rd));
    	{outFile.write(reinterpret_cast<const char *> (&rd), sizeof(rd));}
    }
    I get the following output:
    Code:
    Writing 31,2.34 to 2
    Writing 62,1.55 to 4
    Writing 60,3.25 to 2
    Writing 38,3.9 to 9
    If I change 60 to 61, I get the output
    Code:
    Writing 31,2.34 to 2
    Writing 62,1.55 to 4
    Writing 61,3.25 to 3
    Writing 38,3.9 to 9
    and the file output.data looks like this (which is what I think you wanted):
    Code:
    *< Invalid Records Report >*
    333        3.33
    <* end >*
    
    Reading random file sequentially
    0.)  Empty record
    1.)  Empty record
    2.)  31        2.34
    3.)  61        3.25
    4.)  62        1.55
    5.)  Empty record
    6.)  Empty record
    7.)  Empty record
    8.)  Empty record
    9.)  38         3.9
    10.)  Empty record
    11.)  Empty record
    12.)  Empty record
    13.)  Empty record
    14.)  Empty record
    15.)  Empty record
    16.)  Empty record
    17.)  Empty record
    18.)  Empty record
    19.)  Empty record
    20.)  Empty record
    21.)  Empty record
    22.)  Empty record
    23.)  Empty record
    24.)  Empty record
    25.)  Empty record
    26.)  Empty record
    27.)  Empty record
    28.)  Empty record
    29.)  Empty record
    30.)  Empty record
    I think that's what you should expect, since 60%29 == 2 == 31%29.

    Maybe you were intending to mod with 31 instead of with 29? At the moment, slots 29 and 30 in your pseudo-hash-table will never be used.

    So I guess my question is, what's wrong with it? Why were you expecting the output you gave?
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Unless . . . ah! It is a hash table, a hash table with open addressing -- am I right? So if you're writing something into the file, and the spot is already taken, you want it to e.g. go to the next spot instead. Brain freeze, sorry.

    Well, here's my fix for it. I basically made the output file read as well as write, then before I wrote a record to the file, I would check to see if there was already a record there. If so, I'd advance to the next record and so on.

    There may be other ways to do this, but that's what came to mind. With my code, and your original in.data, the out.data that you wanted gets produced.

    Of course, this means that the table could get full, and I added some code to check for that too. Though I didn't handle it very well, just print a message and let it crash.

    See my attached code. It's really a .zip file, just rename and extract. The crucial code I've reproduced here.

    Code:
    void StudBinaryFile::writeBinary(StudBinaryFile rd, fstream& outFile)
    {
            //std::cout << "Writing " << rd.get_id() << "," << rd.get_gpa()
            //    << " to " << (id % 29) << std::endl;
            
            int original = id % 29;
            
            StudBinaryFile temp;
            for(;;) {
                //std::cout << "Checking " << id % 29 << std::endl;
                outFile.seekp((id % 29) * sizeof(rd));
                if(!outFile.read(reinterpret_cast<char *> (&temp), sizeof(temp))) break;
                //std::cout << "[existing data: " << temp.get_id() << "," << temp.get_gpa() << std::endl;
                if(temp.get_id() != 0) {
                    id ++;
                    
                    if(id == original) {
                        std::cout << "Table full\n";
                        break;
                    }
                }
                else break;
            }
            
    	outFile.seekp((id % 29) * sizeof(rd));
    	outFile.write(reinterpret_cast<const char *> (&rd), sizeof(rd));
            
    }
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  4. #4
    Registered User
    Join Date
    May 2009
    Posts
    2
    Thank you so much for your help. I have another question...lets say in same program i have the input file
    31 2.34
    62 1.55
    60 3.25
    333 3.33
    38 3.90
    -1 // -1 seperates two kind of inputs. Next two input are for random access
    62
    38

    In the same program how can I read the binary file randomely. So basically i want to read the next input from text file and compare it to binary file and then print it in outfile

    Code:
    This is the output I need
    *< Invalid Records Report >*
    333        3.33
    <* end >*
    
    Reading random file sequentially
    0.)  Empty record
    1.)  Empty record
    2.)  31        2.34
    3.)  61        3.25
    4.)  62        1.55
    5.)  Empty record
    6.)  Empty record
    7.)  Empty record
    8.)  Empty record
    9.)  38         3.9
    10.)  Empty record
    11.)  Empty record
    12.)  Empty record
    13.)  Empty record
    14.)  Empty record
    15.)  Empty record
    16.)  Empty record
    17.)  Empty record
    18.)  Empty record
    19.)  Empty record
    20.)  Empty record
    21.)  Empty record
    22.)  Empty record
    23.)  Empty record
    24.)  Empty record
    25.)  Empty record
    26.)  Empty record
    27.)  Empty record
    28.)  Empty record
    29.)  Empty record
    30.)  Empty record
    
    Reading Random Randomly
    7.) 62           1.55
    9.)  38          3.90

  5. #5
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    If you have the binary file already created, and you want to randomly access one record in it, you can use the seekg function of ifstream just as you have done. I think you should be able to figure it out.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Formatting a text file...
    By dagorsul in forum C Programming
    Replies: 12
    Last Post: 05-02-2008, 03:53 AM
  2. Print file in binary mode
    By vikernes in forum C++ Programming
    Replies: 6
    Last Post: 02-25-2006, 12:43 AM
  3. Possible circular definition with singleton objects
    By techrolla in forum C++ Programming
    Replies: 3
    Last Post: 12-26-2004, 10:46 AM
  4. Binary Search Trees Part III
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 10-02-2004, 03:00 PM
  5. Unknown Memory Leak in Init() Function
    By CodeHacker in forum Windows Programming
    Replies: 3
    Last Post: 07-09-2004, 09:54 AM

Tags for this Thread