How does "write" work for ofstream?

From: Mahmood Ahmad (mahmood_siddiqi_at_yahoo.com)
Date: 02/24/04


Date: 24 Feb 2004 06:39:58 -0800

Hello,

I am facing a problem with writing data in a binary file using write
member function of an ofstream object.

My program saves strange characters in the ofstream object valid_file,
strange becuse the characters are unexpected.

The program reads a line from a text file. Each line read contains
record of one of three types IREC, CREC and DREC. All this program
does is read the line, separate the fields into strings, copy those
strings into fields of appropriate record type and write the record
into a binary file.

I have checked and debugged to see if all the strings get the expected
characters (in number and in content). Everything seems to work fine.
However, in the process of closing the file, some thing has gone wrong
which I do not know. Could you please suggest me find ways to
investigate into the problem?

I also do not know how the "write" function actually works, does it
save data to a buffer before saving onto the file OR does it directly
write to the file? My observation (by debugging the program) tells
that the "write" first writes to a buffer. Please suggest to me some
resources for reading about the mechanics of file operations.

I hope the present code is not terribly large. I would appreciate for
your help.

Thanks,

Mahmood.

Here is the code and the example data:

#include <iostream>

using std::cout;
using std::endl;
using std::ios;

#include <string>

using std::string;

#include <fstream>

using std::ifstream;
using std::ofstream;

#include <iomanip>

using std::setprecision;
using std::setiosflags;
using std::resetiosflags;
using std::setw;
//
#include <cstdlib>
#include <ctype.h>
//
#define FOUR 4
#define CUSTCODE 6
#define PARTNUMB 7
#define QUANTITI 5
#define CREDITLIM 8
#define CUSTNAME 21
#define CUSTADDR 61
#define BALANCE 10
//
#define MAXCHARS 103
//
typedef struct {
 char rec_type;
 char cust_code[CUSTCODE];
 char part_num[PARTNUMB];
 char quantity[QUANTITI];
} IREC;
//
typedef struct {
 char rec_type;
 char cust_code[CUSTCODE];
} DREC;
//
typedef struct {
 char rec_type;
 char cust_code[CUSTCODE];
 char cust_name[CUSTNAME];
 char cust_add[CUSTADDR];
 char cust_balance[BALANCE];
 char credit_lim[CREDITLIM];
} CREC;
//
#define IREC_SIZE sizeof(IREC)
#define CREC_SIZE sizeof(CREC)
#define DREC_SIZE sizeof(DREC)
//
ifstream trans_file;
ofstream valid_file;
//
int total_count = 0;
int prn_count = 0;
char valid_char1, valid_char2;
char txtrec[MAXCHARS];
//
bool validate_writeI(char* txtrec);
bool validate_writeC(char* txtrec);
bool validate_writeD(char* txtrec);
//
int main()
{
 bool vflag;
 char mych1;
//
 trans_file.open("mydata.DAT", ios::in);
 if(!trans_file.is_open())
 {
  cout << "Transaction file is not opened" << endl;
  exit(1);
 }
 valid_file.open("mydataVF.DAT", ios::out|ios::binary);
 if(!valid_file.is_open())
 {
  cout << "Validation file is not opened" << endl;
  exit(1);
 }
 while(trans_file && !trans_file.eof())
 {
  trans_file.getline(txtrec, MAXCHARS, '\n');
  mych1 = toupper(txtrec[0]);
  switch(mych1)
  {
  case 'I':
  case 'R':
   {
    vflag = validate_writeI(txtrec);
    total_count++;
    break;
   }
  case 'C':
   {
    vflag = validate_writeC(txtrec);
    total_count++;
    break;
   }
  case 'D':
   {
    vflag = validate_writeD(txtrec);
    total_count++;
    break;
   }
  default:
   break;
  }
  if((mych1 != 'I') && (mych1 != 'R') &&
     (mych1 != 'C') && (mych1 != 'D'))
  {
   if(isalpha(mych1))
   {
    cout << (total_count+1) << "\t"
      << "Invalid record type."
      << endl;
    prn_count++;
    total_count++;
   }
  }
 }
 cout << "Total records checked:\t"
   << total_count << endl << endl;
 cout << "End of file reached. Exitting normally." << endl;
//
 return 0;
}
//
bool validate_writeI(char* txtrec)
{
 bool validation_flag = true;
 IREC irec;
 char mych;
 char s1[CUSTCODE], s2[PARTNUMB], s3[QUANTITI];
//
// First, separating each field into strings
 for(int i=1; i<(IREC_SIZE-3); i++)
 {
  mych = txtrec[i];
  if(i <= (CUSTCODE-1))
   s1[i-1] = mych;
  else if((i > (CUSTCODE-1)) && (i <= (CUSTCODE+PARTNUMB-2)))
   s2[i-CUSTCODE] = mych;
  else
   s3[i-(CUSTCODE+PARTNUMB-1)] = mych;
 }
// Appending null character to the end of each string.
 s1[CUSTCODE-1] = '\0';
 s2[PARTNUMB-1] = '\0';
 s3[QUANTITI-1] = '\0';
// Saving strings into record fields
 irec.rec_type = txtrec[0];
 strncpy(irec.cust_code,s1,CUSTCODE);
 strncpy(irec.part_num,s2,PARTNUMB);
 strncpy(irec.quantity,s3,QUANTITI);
 validation_flag = true;
//
// Saving the record into te binary file.
 IREC *irec_ptr;
 irec_ptr = &irec;
 valid_file.write((char *) irec_ptr, IREC_SIZE);
 return validation_flag;
}
//
bool validate_writeD(char* txtrec)
{
 bool validation_flag = true;
 char mych, s1[CUSTCODE];
 DREC drec;
//
// saving in string
 for (int i=1; i<DREC_SIZE; i++)
 {
  mych = txtrec[i];
  s1[i-1] = mych;
 }
 s1[CUSTCODE-1] = '\0'; // Append null character at the end.
// Save the string in the record
 drec.rec_type = txtrec[0];
 strncpy(drec.cust_code,s1,CUSTCODE);
 cout << "cust_code = " << s1 << endl;
 valid_count++;
 validation_flag = true;
//
// Write record in the file
 DREC *drec_ptr;
 drec_ptr = &drec;
 valid_file.write((char *) drec_ptr, DREC_SIZE);
 return validation_flag;
}
//
bool validate_writeC(char* txtrec)
{
 char s1[CUSTCODE], s2[CUSTNAME], s3[CUSTADDR];
 char s4[BALANCE], s5[CREDITLIM];
 bool validation_flag = true;
 char mych;
//
// separate record fields into strings
 for(int i=1; i < 102; i++)
 {
  mych = txtrec[i];
  if(i <= (CUSTCODE-1))
   s1[i-1] = mych;
  else if((i > (CUSTCODE-1)) && (i <= (CUSTCODE+CUSTNAME-2)))
   s2[i-CUSTCODE] = mych;
  else if((i > (CUSTCODE+CUSTNAME-2)) &&
      (i <= (CUSTCODE+CUSTNAME+CUSTADDR-3)))
   s3[i-(CUSTCODE+CUSTNAME-1)] = mych;
  else if((i > (CUSTCODE+CUSTNAME+CUSTADDR-3))
    && (i <= (CUSTCODE+CUSTNAME+CUSTADDR+BALANCE-4)))
   s4[i-(CUSTCODE+CUSTNAME+CUSTADDR-2)] = mych;
  else
   s5[i-(CUSTCODE+CUSTNAME+CUSTADDR+BALANCE-3)] = mych;
 }
// Append null character at the end
 s1[CUSTCODE-1] = '\0';
 s2[CUSTNAME-1] = '\0';
 s3[CUSTADDR-1] = '\0';
 s4[BALANCE-1] = '\0';
 s5[CREDITLIM-1] = '\0';
// save these strings into the record field
 CREC crec;
 crec.rec_type = txtrec[0];
 strcpy(crec.cust_code, s1);
 strcpy(crec.cust_name, s2);
 strcpy(crec.cust_add, s3);
 strcpy(crec.cust_balance, s4);
 strcpy(crec.credit_lim, s5);
//
 validation_flag = true;
//
// writing record into the file.
 CREC *crec_ptr;
 crec_ptr = &crec;
 valid_file.write((char *)crec_ptr, CREC_SIZE);
 return validation_flag;
}
END OF PROGRAM
File: mydata.dat
I246862456820056
R246802456864089
R357854569002037
D25402
D45900
D4590X
C45675Mahmood Ahmad 16 Greywethers Avenue;Old Town;Swindon
Wiltshire SN3 1QF; 604509.501000000
C45675Mahmood Ahmad Greywethers 16 Avenue;Old Town;Swindon
Wiltshire SN3 QFF; 604509.501000000
C45675Mahmood A9mad 16 Greywethers Avenue;Old Town;Swindon
Wiltshire SN3 1QF; 604509.501000000
C90875Mrs Gwen Metcalfe 10 Bydemill Gardens;Highworth
Swindon;Wiltshire;SN6 7BT 455609.752500000
C90875Mrs Gwen Metcalfe 10 Bydemill Gardens;Highworth
Swindon;Wiltshire;SN6 7BT 455609.752500M00
C90875Mrs Gwen Metcalfe 10 Bydemill
Gardens;Highworth;Swindon;Wiltshire;SN6 7BT 455609.752500000
D29904
C99996Mr D Gupta Ridgeway Hospital;Moremead Road;Wroughton
Swindon;SN4 4DD 009000.000400000
R00121450500987
M34002
D34002



Relevant Pages

  • Re: heeeeeeeeeeeeeeeellllllllllllllppppppppppppppppppppp
    ... This means that if you develop the bad habit of using char * (left over ... It usually takes me five minutes to create a Unicode version of any of my apps, ... BOOL and bool are different data types. ... can be up to MAX_PATH characters). ...
    (microsoft.public.vc.mfc)
  • Re: somebody dropped a (warning) bomb
    ... If one actually needs to compare alphabetic characters numerically, ... Char values are indexes in a character set. ... char strings are often signed char strings, ... you in fact don't solve initial problem of comparing ...
    (Linux-Kernel)
  • Re: sort problem
    ... AS> # Set $order{$char} to increasing values in the sequence we want ... No, i mean "characters". ... strings and the number of hash keys. ... "Reply" at the bottom of the article headers. ...
    (comp.lang.perl.misc)
  • Re: Abnormal program termination - Please help!
    ... does is read the line, separate the fields into strings, copy those ... char valid_char1, valid_char2; ... bool validate_writeI(char* txtrec); ...
    (comp.lang.cpp)
  • Re: sort problem
    ... AS> # Set $order{$char} to increasing values in the sequence we want ... AS> single-byte characters is irrelevant. ... AS> they are strings, not integers. ... perl strings. ...
    (comp.lang.perl.misc)