Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

File Processing via seekp and seekg C++

  1. Feb 17, 2009 #1
    Hello,

    I am working on a program about credit card that basically, generate 16 ramdom digits, a starting balance and write it to a file. The file works as an database and can be updated later.

    Here is my credit card class

    Code (Text):
    class CCard
    {
    // variables section
    private:
        //sixteen digits of a credit card
        int group1[4];
        int group2[4];
        int group3[4];
        int group4[4];
        double balance;
        double cardNumber;
        int ID;

    // methods sections
    public:
        CCard(int=0); // constructor
        double getAccount() const; // return account number
        double getBalance() const; // return balance number
        void setBalance(double);
        void resetGroups(); // initialize 16 digits to 0
       
    private: //should not be accessible by outside objects.
       
        int randomNumber(); // return random number from 0->9
        void setRandNumberToCard(); // set random number for card
        int calculateCheckDigit(); // find the last digit of the card
        double arrayToNumber(int [], double); // convert array of int to a double number
        void convertGroupsToCardNumber(); //convert 16 digits to cardNumber (account)
    };
    Here is the method to create a random access file which can hold 1000 record

    Code (Text):
    void createFile()
    {
        ofstream file("data.dat",ios::out|ios::binary);
        if (!file){
            cerr << "File could not be opended" << endl;
            exit(1);
        }
       
        // empty object, all the value is 0
        CCard card;

        card.resetGroups();
        //create 1000 accounts
        for (int i = 0; i < 1000; i++)
        {
            file.write(reinterpret_cast<const char *>(&card),sizeof(CCard));   
        }
        file.close();
    }
    Here is the method of writing new record to the file (does not work somehow)

    Code (Text):

    void newRecord(fstream &insertFile)
    {
        double acc = 0.0;
        cout << "\nEnter 3-7 :"; //possible starting digits of a credit card
        cin >> acc;
       
        //create an object which include 15 random digits of a card and balance
        CCard card(acc);
       
        // get the 16 digits account number (generated randomly)
        double accountNumber = card.getAccount();
       
        //move the pointer to the place
        insertFile.seekp((accountNumber -1)*sizeof(CCard));

        //write to the place (assume the place is empty)   
        insertFile.write(reinterpret_cast<char *>(&card),sizeof(CCard));
    }

    Any input would be appreciated.

    Regard,
     
    Last edited: Feb 17, 2009
  2. jcsd
  3. Feb 17, 2009 #2

    rcgldr

    User Avatar
    Homework Helper

    Did you open the file as read and write (replacement allowed) or write only (creation)?

    ofstream file("data.dat",ios::in|ios::eek:ut|ios::binary);

    Do fstream files support write in place?
     
    Last edited: Feb 17, 2009
  4. Feb 17, 2009 #3
    Dear Reid,

    Yeah, I think I did.
    Here is the code in main

    Code (Text):
    int main()
    {

        //createFile();
        fstream file("data.dat",ios::in|ios::out|ios::binary);
        if (!file)
        {
            cerr << "Can't open file";
            exit(1);
        }

        int choice;

        while ((choice = enterChoice()) != 4)
        {
            switch (choice)
            {
            case 1: display(file);break;
            case 2: updateRecord(file);break;
            case 3: newRecord(file);break;
            default: cerr << "incorrect choice";
                break;
            }
            file.clear();
        }
        file.close();
       
        cin.ignore();
        cin.ignore();
        return 0;
    }
    PM me if you need the full source I am working on :(
     
    Last edited: Feb 17, 2009
  5. Feb 17, 2009 #4

    rcgldr

    User Avatar
    Homework Helper

    What does file.clear() do?

    If you open up the file with a binary editor what is going on?
     
  6. Feb 17, 2009 #5
    Hi Reid,
    the file.clear(); is to reset end-of-file indicator.
    I never heard of a binary editor before :(
    I use notepad to open up the data.dat file after generated 1000 empty records... it shows garbage.
    like this :

    ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ
    ...

    Interestingly, if I read from that file ( the data.dat )into a normal txt in nonbinary mode, it show correctly:

    0 0 0
    0 0 0
    0 0 0
    0 0 0
    ... (repeated 1000 times)

    Here is the code:
    Code (Text):
    void display (fstream &readFile)
    {
        ofstream outPrintFile("print.txt",ios::out);

        if (!outPrintFile)
        {
            cerr << "File could not be created";
            exit(1);
        }
       
        // put the pointer into the beginning of the file
        readFile.seekg(0);

        CCard card;
        readFile.read(reinterpret_cast<char *>(&card),sizeof(CCard));

        while(!readFile.eof())
        {
            if(card.getID() != 0) // skip it if you want to show zeros
            outputLine(outPrintFile,card);

            readFile.read(reinterpret_cast<char *>(&card),sizeof(CCard));  
        }
        cout << "\ndone";
    }
     
    Code (Text):

    void outputLine(ostream &output, const CCard &record)
    {
        output << setprecision(20) << " " << record.getAccount() << " " << record.getBalance() << " " << record.getID() << endl;

        //cout << "\n account is: " << record.getAccount() << endl << "Balance is: " << record.getBalance();
    }
    but the bottom line is the method to create newRecord (actually, it is to insert a generated object into the empty record in the data.dat) doesn't work. This project dues this Saturday... beside, I have another huge Java project dues the same day but haven't started it yet since I stuck with the C++ here :(
     
    Last edited: Feb 17, 2009
  7. Feb 18, 2009 #6

    rcgldr

    User Avatar
    Homework Helper

    What C++ compiler are you using? Microsoft's Visual Studio's open file dialog box includes a down arrow on the open button (enabled after you click on a file name) that lets you select "open with", where you can then specify "binary editor". If you change the name of the file to "data.bin", generally most programming editors will default to binary mode when you open the file.

    Link to what should be a working example:

    http://www.cplusplus.com/reference/iostream/ostream/seekp.html

    Also, you might need to do a flush after each write.
    insertFile.write(...)
    insertFile.flush()

    More on fstream (I haven't used fstream class before, so this link is mostly for me):

    http://www.cplusplus.com/reference/iostream/fstream
     
    Last edited by a moderator: Apr 24, 2017
  8. Feb 18, 2009 #7
    Thanks Reid for the binary :D
    I use VS 2008 Pro SP1. It is now showing in binary mode now.
    I think the error (doesn't write) is actually because of the nature of create 1000 empty objects. When the method create file with 1000 empty slots and set them into a file, their location will be

    Code (Text):
    // put the pointer to the position of the appropriate place (min 0 to 999 max depends)
    // example
    insertFile.seekp ((from 0 to 999)*reinterpret_<cast char *>sizeof (CCard));
     
    The problem is that I use credit card number (16 digits which equivalent to some trillions perhaps) and try to plug it into the file, which does not have the appropriate room because it only have room from 0 to 999.

    Code (Text):
    insertFile.seekp((accountNumber -1)*sizeof(CCard)); // the accountNumber is way too big
    // I think unless the file extends to some trillion records, then it could work
    insertFile.write(reinterpret_cast<char *>(&accountNumber-1),(sizeof(CCard));
    I tried replacing the accountNumber - 1 with the balance (which is maximum $1000 in this particular program) and it did write :)
     
  9. Feb 18, 2009 #8

    rcgldr

    User Avatar
    Homework Helper

    I knew the account numbers had 16 digits, but wrongly assumed you would limit the values to 1 -> 1000 based on the code. You'll need to initialize the file with "empty" records, some "reserved" or illegal value in one of the class fields to indicate that record in the file is empty. Then when you need to add a new record, just scan the file by reading records sequentially until you find an empty slot and write the record there.

    With the short time period for the project, I assume you're not expected to optimize the searching process with some type of hashing algorithm or sorting and binary searching?
     
  10. Feb 18, 2009 #9
    Hello Reid,

    Thanks a lot. I suspected it was wrong but kept trying somehow :(
    I think it is self sorted in binary file? Instead of using 16 digits to move the pointer, I now use the last four digits. The possibility is 0 -> 9999 so I just need 10000 empty records to store them. When I use
    insertFile.seekp((lastFourDigit -1)*sizeof (CCard));
    It would place the pointer into a unique position on the record file Data.dat, thus when I print them out, I would expect them sorted by lastFourDigit order?

    I wonder if you have some performance experience with such approach vs hashing algorithm?
     
  11. Feb 18, 2009 #10

    rcgldr

    User Avatar
    Homework Helper

    As long as those last four digits are different for every number that wil work.

    Since the value is 0->9999, the you'd wouldn't subtract 1: insertFile.seekp((lastFourDigit)*sizeof (CCard)).

    For a 1000 records on a homework program it's not worth the effort. Since you're directly accessing the records via the last 4 digits, which are assumed to be unique, you're directly indexing off a value, so no need to use a hashing algorithm which would convert a 16 digit number into a semi-unique 4 digit number, for the initial probe into the file, followed by more probes (adding a prime number to the index | 10000 would probably be good enough) until you find a match or empty slot.
     
    Last edited: Feb 18, 2009
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook




Similar Discussions: File Processing via seekp and seekg C++
  1. C++ file i/o (Replies: 7)

  2. C++ csv file reading (Replies: 2)

Loading...