Data file handling

When I read records (block I/O) from file to display it using the write function, the last record is displayed twice. How do I fix this?

Comments

  • [color=Blue]
    1. Without code can't say...
    2. Step through your code in debugger - it's a lot of fun!
    [/color]
  • Well, the code goes like this. I know how to fix this problem for the display module after my teacher told me, but the Insert and Modify module's not working properly. The last record in the file is being stored twice in both the cases. Please help me immediately because I need data file handling for my project.

    #include
    #include
    #include
    #include
    #include

    class Account
    {
    private:
    int accno;
    char cname [21];
    float balance;
    public:
    void Input ();
    void Display ();
    int Retaccno ();
    } acc;

    void Account :: Input ()
    {
    cout << "


    Enter the account number here :- ";
    cin >> accno;
    cout << "


    Enter the customer name here :- ";
    gets (cname);
    cout << "


    Enter the balance here :- Rs. ";
    cin >> balance;
    }

    void Account :: Display ()
    {
    cout << "


    Account number : " << accno << " Customer name : " << cname << " Balance : Rs. " << balance;
    }

    int Account :: Retaccno ()
    {
    return accno;
    }

    void Create ()
    {
    int x = remove ("c:\dfh7.txt");
    fstream f ("c:\DFH7.txt", ios :: in | ios :: out | ios :: binary );
    if(! f)
    {
    clrscr ();
    cout << "


    Error in opening the file. Aborting!!!";
    getch();
    exit(0);
    }
    int n;
    clrscr ();
    cout << "


    Enter the number of customers here :- ";
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
    clrscr ();
    cout << "


    Enter the details for customer number " << i << " here :- ";
    acc.Input ();
    f.write ((char *) & acc, sizeof (Account));
    }
    f.close ();
    }

    void Add ()
    {
    ofstream out ("c:\DFH7.txt", ios :: app | ios :: binary );
    if(! out)
    {
    clrscr ();
    cout << "


    Error in opening the file. Aborting!!!";
    getch();
    exit(0);
    }
    int n;
    clrscr ();
    cout << "


    Enter the number of records you want to add here :- ";
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
    clrscr ();
    cout << "


    Enter the details of customer " << i << " here :- ";
    acc.Input ();
    out.write ((char *) & acc, sizeof (Account));
    }
    out.close ();
    }

    void Insert ()
    {
    ifstream in ("c:\dfh7.txt", ios :: in | ios :: binary);
    if(! in)
    {
    clrscr ();
    cout << "Error in opening the file. Aborting!!!";
    getch();
    exit(0);
    }
    ofstream out ("c:\dfh7t.txt");
    if(! out)
    {
    clrscr ();
    cout << "Error in opening the file. Aborting!!!";
    getch();
    exit(0);
    }

    int n;
    Account temp;
    clrscr ();
    cout << "


    Enter the record number after you want to insert the record here :- ";
    cin >> n;
    clrscr ();
    cout << "


    Enter the account details here :- ";
    temp.Input ();
    while (! in.eof ())
    {
    int x = out.tellp ();
    if (x == n * sizeof (Account))
    out.write ((char *) & temp, sizeof (Account));
    else
    {
    in.read ((char *) & acc, sizeof (Account));
    out.write ((char *) & acc, sizeof (Account));
    }
    }
    in.close ();
    out.close ();
    int x = remove ("c:\dfh7.txt");
    rename ("c:\dfh7t.txt", "c:\dfh7.txt");
    }

    void Search ()
    {
    ifstream in ("c:\dfh7.txt");
    if(! in)
    {
    clrscr ();
    cout << "Error in opening the file. Aborting!!!";
    getch();
    exit(0);
    }

    int flag = 0, n;
    clrscr ();
    cout << "


    Enter the account number you want to search for here :- ";
    cin >> n;
    in.seekg (0);
    while (! in.eof ())
    {
    in.read ((char *) & acc, sizeof (Account));
    if (acc.Retaccno () == n)
    {
    flag = 1;
    cout << "


    Record found. Press any key to continue.....";
    clrscr ();
    cout << "


    Te details of the required customer are :- ";
    acc.Display ();
    getch ();
    break;
    }
    }
    if (flag == 0)
    {
    cout << "


    Record not found!";
    getch ();
    }
    in.close ();
    }

    void Modify ()
    {
    ifstream in ("c:\dfh7.txt", ios :: in | ios :: binary);
    ofstream out ("c:\dfh7t.txt", ios :: out | ios :: binary);
    if(! in || ! out)
    {
    clrscr ();
    cout << "Error in opening the file. Aborting!!!";
    getch();
    exit(0);
    }

    int n, flag = 0;
    clrscr ();
    cout << "


    Enter the account number of the customer whose details you

    want to modify here :- ";
    cin >> n;
    while (! in.eof ())
    {
    in.read ((char *) & acc, sizeof (acc));
    if (acc.Retaccno () == n)
    {
    flag = 1;
    cout << "


    Record found. Press any key to continue.....";
    getch ();
    clrscr ();
    cout << "


    Enter the new details for the customer here :- ";
    acc.Input ();
    out.write ((char *) & acc, sizeof (acc));
    }
    else
    out.write ((char *) & acc, sizeof (Account));
    }
    if (flag == 0)
    {
    cout << "


    Record not found!";
    getch ();
    }
    in.close ();
    out.close ();
    remove ("c:\dfh7.txt");
    rename ("c:\dfh7t.txt", "c:\dfh7.txt");
    }

    void Delete ()
    {
    ifstream in ("c:\dfh7.txt", ios :: in | ios :: binary);
    ofstream out ("c:\dfh7t.txt", ios :: out | ios :: binary);
    int n, flag = 0;
    if (! in || ! out)
    {
    clrscr ();
    cout << "


    Error in file opening. Aborting!!!";
    getch ();
    exit (0);
    }
    clrscr ();
    cout << "


    Enter the account number of the customer, whose record

    you want to delete, here :- ";
    cin >> n;
    while (! in.eof ())
    {
    in.read ((char *) &acc, sizeof (Account));
    if (acc.Retaccno () == n)
    {
    flag = 1;
    cout << "


    Record found and deleted!";
    getch ();
    }
    else
    out.write ((char *) &acc, sizeof (Account));
    }
    if (flag == 0)
    {
    cout << "


    Record not found!";
    getch ();
    }
    in.close ();
    out.close ();
    remove ("c:\dfh7.txt");
    rename ("c:\dfh7t.txt", "c:\dfh7.txt");
    }

    void Display ()
    {
    ifstream in ("c:\dfh7.txt", ios :: in | ios :: binary);
    if(! in)
    {
    clrscr ();
    cout << "Error in opening the file. Aborting!!!";
    getch();
    exit(0);
    }

    clrscr ();
    cout << "


    The details for the customers are :-";
    in.read ((char*) & acc, sizeof (Account));
    while (! in.eof ())
    {
    acc.Display ();
    in.read ((char*) & acc, sizeof (Account));
    }
    getch ();
    in.close ();
    }

    void main ()
    {
    int choice;

    do
    {
    clrscr ();
    cout << "


    DATA FILE HANDLING";
    cout << "


    1. Create";
    cout << "


    2. Add";
    cout << "


    3. Insert";
    cout << "


    4. Search";
    cout << "


    5. Modify";
    cout << "


    6. Delete";
    cout << "


    7. Display all";
    cout << "


    8. Exit";
    cout << "


    Enter your choice here :- ";
    cin >> choice;
    switch (choice)
    {
    case 1 : Create (/*acc*/);
    break;
    case 2 : Add (/*acc*/);
    break;
    case 3 : Insert (/*acc*/);
    break;
    case 4 : Search (/*acc*/);
    break;
    case 5 : Modify (/*acc*/);
    break;
    case 6 : Delete (/*acc*/);
    break;
    case 7 : Display (/*acc*/);
    break;
    case 8 : break;
    default : cout << "


    Invalid choice. Try again!";
    getch ();
    }
    } while (choice != 8);
    }
  • Please use code tags when posting code samples in the future.

    [code]while (! in.eof ())[/code]

    I would be very suspicious of any bit of code that test EOF to control a loop. In most cases this is the wrong way to go about doing things and can easily lead to the problem you are describing (last line duplicated). The problem is that the EOF flag is not set when you reach the physical end of file but rather once you've attempted to read past the end of the file. After you read the last bit of data from the file, EOF still says false and you enter your loop. Once you are in the loop you've already shot yourself in the foot because you are then processing data when there is no more to process. Your read attempt will then fail (EOF at this point will return true) and you wind up processing data that's left over from the last successful read attempt and this is where the duplicate data comes from.

    The correct way to loop through the file is to test the read operation itself and not EOF. The read operation returns a value which can be used to determine if the read was good or not. If good, then you can go into the loop and process the data that you've read. If not, then you should not go into the loop at all.
  • Thaks HK_MP5KPDW. However, could you explain with a code.....
  • I *think* you can use ifstream object.peek() to determine whether or not the EOF bit is next; however, I haven't used C++ in years, so I can't recall if it's good practice or not.

    [code]
    int ch;
    ifstream infile;

    while((ch = infile.peek()) != EOF) {
    // process as before
    }
    [/code]

    I also can't recall if it has a side effect of skipping the last record inside of the loop. If so, just read your input stream again after the loop exits.
  • Using getline as an example, many people first starting out doing file I/O would try the following to read and print a line from a file:
    [code]ifstream file;
    string line;

    ...

    while(!file.eof())
    {
    getline(file,line); // Read a line
    cout << line << endl; // Print the line
    }[/code]
    This is wrong because after the last is read, EOF still returns false and you would therefore end up going into the loop body. Once inside such a loop it's already to late, you've committed yourself to reading a line and printing it out. Since we are at the end of the file, the [italic]getline[/italic] will fail (testing EOF at this point would return true). Since the [italic]getline[/italic] fails, the previous data stored in the string remains unaffected and that same last line is what would then get output resulting in an apparent duplicate line.

    The better way of dealing with such a scenario is to test the return result of the [italic]getline[/italic] call instead of EOF. This would look like so:
    [code]ifstream file;
    string line;

    ...

    while(getline(file,line)) // Get a line
    {
    cout << line << endl; // Print the line
    }[/code]
    This works because the [italic]getline[/italic] function returns a reference to the stream (in this case the [italic]ifstream[/italic] object called "file") and in the context of the [italic]while[/italic] loops conditional, can be evaluated in a true/false sense. Essentially this code is saying "as long as I've successfully read a line, print it". The loop body is only ever entered if we've got something to read from the file.

    It's also possible to do something closer to what you were attempt with the testing of EOF but it looks sloppier. The EOF test must be made immediately after the read attempt - [u]and before you perform the write operation[/u] - in order to properly trap the condition where we've just tried to read past the end of the file. If the EOF test returns true, then you'd need to call break to exit the [italic]while[/italic] loop so you don't try to mistakenly output duplicate data. That method would look like this:
    [code]ifstream file;
    string line;

    ...

    while(1)
    {
    getline(file,line); // Read a line
    if(file.eof()) // If we are at the end of the file...
    break; // ...then exit from the loop before we output
    cout << line << endl; // Print the line
    }[/code]
  • Well, thanks people for your replies. However, I tried a new code and it works.....

    while (!f.eof ())
    {
    f.read ((char *) &handle_name, sizeof (record));
    if (!f.good ())
    break;
    //Else, the operation continues....
    }


  • This post has been deleted.
  • This post has been deleted.
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories