Home

File Processing

 

C File Processing

 

C How To Process Files

File processing is traditionally performed using the FILE class. In the strict C sense, FILE is a structure and it is defined in the stdio.h header file. This object is equipped with variables used to indicate what operation would be performed. To use this structure, you can first declare an instance of the FILE structure. Here is an example:

FILE *Starter;

After instantiating the structure, you can define what to do with it, using one of the provided functions. Because FILE was created as a C structure, it does not have member functions. The functions used to perform its related operations on files are also declared in the stdio.h header file.

 

Practical Learning Practical Learning: Preparing for File Processing

  1. Start Borland C++ Builder and create a new VCL Forms Application
  2. To save the project, on the Standard toolbar, click the Save All button
  3. Create a new folder named Students Grades
  4. Save the unit as Main and save the project as Grades
  5. Change the Caption of the form to Students Grades and change its Name to frmMain
  6. From the Additional tab of the Tool Palette, add three Bevel and one Panel controls. Design them as follows:
     
  7. From the Standard section of the Tool Palette, add the Labels, one ComboBox, and Edit controls as follows:
     
  8. Name the Edit and the ComboBox controls after their accompanying labels: edtFirstName, edtMI, edtLastName, edtDOB, cboGender, edtEnglish, edt2ndLanguage, edtHistory, edtGeography, edtSciences, and edtSports
  9. On the form, click the combo box and, in the Object Inspector, double-click the right field of its Items property
  10. Add three lines as Unknown, Male, and Female
  11. Click OK
  12. From the Additional tab of the Tool Palette, click the BitBtn control and click in the top Bevel.
  13. Change its properties as follows:
    Caption = &New
    Glyph = New2
    Name = btnNew
  14. Double-click the New button and implement its OnClick event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::btnNewClick(TObject *Sender)
    {
        edtFirstName->Text   = "";
        edtMI->Text          = "";
        edtLastName->Text    = "";
        edtDOB->Text         = "";
        cboGender->ItemIndex = 0;
        edtEnglish->Text     = "0.00";
        edt2ndLanguage->Text = "0.00";
        edtHistory->Text     = "0.00";
        edtGeography->Text   = "0.00";
        edtSciences->Text    = "0.00";
        edtSports->Text      = "0.00";
    }
    //---------------------------------------------------------------------------
  15. Double-click an unoccupied area on the form to access its OnCreate event and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::FormCreate(TObject *Sender)
    {
        btnNewClick(Sender);
    }
    //---------------------------------------------------------------------------
  16. Save the project

Opening and/or Saving Files

To create a new file, open an existing file, or save a file, you use the fopen() function. Its syntax is:

FILE *fopen(const char *FileName, const char *Mode);

The first argument, FileName, must be a valid name of a file. If the user is creating or saving a new file, you can let him specify the name of the file, following the rules of the operating system. If the user is opening an existing file, you can make sure the file really exists, retrieve its name and pass it to the fopen() function.

Because the fopen() function is used to save a new file, to open an existing one, or to save a file that was only modified, the second argument, Mode, actually allows you to decide what operation the function will be used to perform. This argument is a short string of one or two characters and can be one of the following:

Mode Role If the file already exists If the file does not exist
r Opens an existing file for reading only. it would be opened and can be read. After the file is opened, the user cannot add data to it. the operation would fail.
w Saves a new file. the file's contents would be deleted and replaced by the new content. a new file is created  and can be written to.
a Opens an existing file, saves new file, or saves a existing file that has been modified. the file is opened and can be modified or updated. New information written to the file would be added to the end of the file. a new file is created  and can be written to.
r+ Opens an existing file. the file is opened and its existing data can be modified or updated. the operation would fail.
w+ Creates new file or saves an existing one. the file is opened, its contents would be deleted and replaced with the new contents. a new file is created  and can be written to.
a+ Creates a new file or modifies an existing one. it is opened and its contents can be updated. New information written to the file would be added to the end of the file. a new file is created  and can be written to.

If the operation performed using the fopen() function is successful, the function returns a pointer to the FILE instance that was declared. The FILE structure is usually used in C and C++ console programs that must conform to console applications. However, when used in VCL applications, because applications are created in a visual development, you should let the users use the Save and Open common dialog boxes that they are used to. In this case, if the user is opening a file, you can pass the FileName member variable of the common dialog box to the fopen() function. Because the fopen() function takes a pointer to char while the Save and Open dialog boxes use AnsiString members, you should convert The TOpenDialog::FileName or the TSaveDialog::FileName to a C string.

After using a file, you should/must close its stream. This is done using the fclose() function. Its syntax is:

int fclose(FILE *stream);

To use this function, you must let it know what instance of the FILE object you are closing.

Practical Learning Practical Learning: Opening and Saving Files

  1. From the Dialogs tab of the Tool Palette, click the OpenDialog button and click anywhere in the form
  2. On the Object Inspector, change its DefaultExt to rcd
  3. In its Filter field, type
    Student Record (*.rcd)|*.rcd|All Files
  4. From the Dialogs tab of the Tool Palette, click the SaveDialog button and click anywhere in the form
  5. On the Object Inspector, change its DefaultExt to rcd and, in its Filter field, type
    Student Record (*.rcd)|*.rcd|All Files
     
  6. On the top section of the Main.cpp file, include the stdio library file as follows:
     
    //---------------------------------------------------------------------------
    #include <vcl.h>
    #include <cstdio>
    using namespace std;
    #pragma hdrstop
    
    #include "Main.h"
    //---------------------------------------------------------------------------
  7. To perform the opening of a record, on the form, double-click the Open button and implement its OnClick event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::btnOpenClick(TObject *Sender)
    {
    	FILE *FOpen;
    
    	if( OpenDialog1->Execute() )
    	{
    		FOpen = fopen(OpenDialog1->FileName.c_str(), "r+");
    
    		if( FOpen == NULL )
    		{
    			ShowMessage("The file could not be opened");
    			return;
    		}
    	}
    
    	fclose(FOpen);
    }
    //---------------------------------------------------------------------------
  8. To perform the saving of a record, on the form, double-click the Save button and implement its OnClick event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::btnSaveClick(TObject *Sender)
    {
    	FILE *FSave;
    
    	if( SaveDialog1->Execute() )
    	{
    		FSave = fopen(SaveDialog1->FileName.c_str(), "w");
    
    		if( FSave == NULL )
    		{
    			ShowMessage("The file could not be saved");
    			return;
    		}
    	}
    
    	fclose(FSave);
    }
    //---------------------------------------------------------------------------
  9. Save the project

Reading From and Writing to Files

To save a file, you must write data to its contents. This operation is performed using the fprintf() or the fwprintf() functions. Their syntaxes are:

int fprintf(FILE *stream, const char *format, ...);
int fwprintf(FILE *stream, const wchar_t *format, ...);

Each one of these functions takes a few arguments depending on how it is used. The first argument, stream, must be an instance of a FILE structure.

The second argument is a string that specifies how data will be formatted and possibly positioned in the stream instance.The string typically starts with the % symbol followed by one or more characters that represents a format. Different formats are used depending on the type of data of the variable that is being written. You can use one the following characters:

Character Used for
c A single character
d An integer
e A floating-point number
f A floating-point number
g A floating-point number
h A short integer
i A decimal, a hexadecimal, or an octal integer
o An octal integer
s A string followed by a white space character
u An unsigned decimal integer
x A hexadecimal integer

After specifying the format, you can type the name of the variable that is being saved. You can repeatedly use the fprintf() function for each variable you want to save. If you have opened a file and want to retrieve data stored from it, you can use the fscanf() or the fwscanf() function. Their syntaxes are:

int fscanf(FILE *stream, const char *format[, address, ...]);
int fwscanf(FILE *stream, const wchar_t *format[, address, ...]);

The first argument, stream, must be a valid instance of a FILE structure. The second argument, format, follows the same rules as for the fprintf() and the fwprintf() functions. After typing the format, type the name of the variable that is being retrieved.

Practical Learning Practical Learning: Reading to and Writing From Files

  1. In the Main.cpp file, change the OnClick event of the Open button as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::btnOpenClick(TObject *Sender)
    {
    	FILE *FOpen; 
    
    	char FirstName[30], LastName[30], DOB[40];
    	int Gender;
    	char English[6], Language2[6], History[6],
    	Geography[6], Sciences[6], Sports[6];
    
    	if( OpenDialog1->Execute() )
    	{
    		FOpen = fopen(OpenDialog1->FileName.c_str(), "r+");
    
    		if( FOpen == NULL )
    		{
    			ShowMessage("The file could not be opened");
    			return;
    		}
    
    		fscanf(FOpen, "%s", FirstName);
    		fscanf(FOpen, "%s", LastName);
    		fscanf(FOpen, "%s", DOB);
    		fscanf(FOpen, "%d", &Gender);
    		fscanf(FOpen, "%s", English);
    		fscanf(FOpen, "%s", Language2);
    		fscanf(FOpen, "%s", History);
    		fscanf(FOpen, "%s", Geography);
    		fscanf(FOpen, "%s", Sciences);
    		fscanf(FOpen, "%s", Sports);
    
    		edtFirstName->Text = FirstName;
    		edtLastName->Text = LastName;
    		edtDOB->Text = DOB;
    		cboGender->ItemIndex = Gender;
    		edtEnglish->Text = English;
    		edt2ndLanguage->Text = Language2;
    		edtHistory->Text = History;
    		edtGeography->Text = Geography;
    		edtSciences->Text = Sciences;
    		edtSports->Text = Sports;
    	}
    
    	fclose(FOpen);
    }
    //---------------------------------------------------------------------------
  2. In the Main.cpp file, change the OnClick event of the Save button as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::btnSaveClick(TObject *Sender)
    {
    	FILE *FSave;
    
    	char FirstName[30], LastName[30], DOB[40];
    	int Gender;
    	double English, Language2, History, Geography, Sciences, Sports;
    
    	strcpy(FirstName, edtFirstName->Text.c_str());
    	strcpy(LastName, edtLastName->Text.c_str());
    	strcpy(DOB, edtDOB->Text.c_str());
    	Gender = cboGender->ItemIndex;
    
    	English = StrToFloat(edtEnglish->Text);
    	Language2 = StrToFloat(edt2ndLanguage->Text);
    	History = StrToFloat(edtHistory->Text);
    	Geography = StrToFloat(edtGeography->Text);
    	Sciences = StrToFloat(edtSciences->Text);
    	Sports = StrToFloat(edtSports->Text);
    
    	if( SaveDialog1->Execute() )
    	{
    		FSave = fopen(SaveDialog1->FileName.c_str(), "w");
    
    		if( FSave == NULL )
    		{
    			ShowMessage("The file could not be opened");
    			return;
    		}
    
    		fprintf(FSave, "%s\n", FirstName);
    		fprintf(FSave, "%s\n", LastName);
    		fprintf(FSave, "%s\n", DOB);
    		fprintf(FSave, "%d\n", Gender);
    		fprintf(FSave, "%.2f\n", English);
    		fprintf(FSave, "%.2f\n", Language2);
    		fprintf(FSave, "%.2f\n", History);
    		fprintf(FSave, "%.2f\n", Geography);
    		fprintf(FSave, "%.2f\n", Sciences);
    		fprintf(FSave, "%.2f\n", Sports);
    	}
    
    	fclose(FSave);
    }
    //---------------------------------------------------------------------------
  3. Save and test the application
     
  4. After using it, close it and return to Borland C++ Builder

C++ File Streaming

 

Overview

File processing in C++ is performed using the fstream class. Unlike the FILE structure, fstream is a complete C++ class with constructors, a destructor and overloaded operators.

To perform file processing, you can declare an instance of an fstream object. If you do not yet know the name of the file you want to process, you can use the default constructor.

Unlike the FILE structure, the fstream class provides two distinct classes for file processing. One is used to write to a file and the other is used to read from a file.

Saving a File

Saving a file consists of writing data to disk. To do this, first declare an instance of the ofstream class using one of its constructors from the following syntaxes:

ofstream(const char* FileName, int FileMode);
ofstream();

The ofstream(const char* FileName, int FileMode) constructor provides a complete mechanism for creating a file. It does this with the help of its two arguments. The first argument, FileName, is a string that specifies the name of the file that needs to be saved. The second argument, FileMode, specifies what kind of operation you want to perform on the file. It can be one of the following:

Mode Description
ios::app If FileName is a new file, data is written to it.
If FileName already exists and contains data, then it is opened, the compiler goes to the end of the file and adds the new data to it.
ios::ate If FileName is a new file, data is written to it and subsequently added to the end of the file.
If FileName already exists and contains data, then it is opened and data is written in the current position.
ios::in If FileName is a new file, then it gets created fine as an empty file.If FileName already exists, then it is opened and its content is made available for processing.
ios::out If FileName is a new file, then it gets created fine as an empty file. Once/Since it gets created empty, you can write data to it.
If FileName already exists, then it is opened, its content is destroyed, and the file becomes as new. Therefore you can create new data to write to it. Then, if you save the file, which is the main purpose of this mode, the new content is saved it.*This operation is typically used when you want to save a file.
ios::trunc If FileName already exists, its content is destroyed and the file becomes as new.
ios::nocreate If FileName is a new file, the operation fails because it cannot create a new file.
If FileName already exists, then it is opened and its content is made available for processing.
ios::noreplace If FileName is a new file, then it gets created fine.
If FileName already exists and you try to open it, this operation would fail because it cannot create a file of the same name in the same location.

Image you have a form with three edit boxes whose job is to get the first name, the last name, and the age of a student:

Control Name Caption/Text Other Properties
Bevel      
Label   First Name:  
Edit edtFirstName    
Label   Last Name:  
Edit edtLastName    
Label   Age:  
Edit edtAge    
Bevel      
BitBtn btnOpen Open  
BitBtn btnSave Save  
BitBtn     Kind: bkClose
OpenDialog      
SaveDialog      

You can save its data using a SaveDialog as follows:

//---------------------------------------------------------------------------
#include <vcl.h>
#include <fstream>
using namespace std;
#pragma hdrstop

#include "Exercise.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnSaveClick(TObject *Sender)
{
	char FirstName[30], LastName[30];
	int Age;

	strcpy(FirstName, edtFirstName->Text.c_str());
	strcpy(LastName, edtLastName->Text.c_str());
	Age = edtAge->Text.ToInt();

	if( SaveDialog1->Execute() )
	{
		ofstream Students(SaveDialog1->FileName.c_str(), ios::out);
		Students << FirstName << "\n" << LastName << "\n" << Age;
	}
}

The default constructor, ofstream(), can be used to create an empty stream if you do not yet have enough information about the file you intend to deal with and what type of operation you will perform. This constructor is used if you plan to call member methods to perform the desired file processing.

After declaring an instance of the ofstream class, you can use the ofstream::open() method to create the file. The syntax of the open() method is:

void open( const char* FileName, int FileMode);

This method behaves exactly like, and uses the same arguments as, the constructor we described above. The first argument represents the name of the file you are dealing with and the FileMode argument follows the modes of the above table.

Because the fstream class in this case is declared as ofstream, the compiler is aware that you want to save a file (in reality, the use of ofstream means that you want to write to a file, in other words you want the FileMode with a value of ios::out), you can use the first constructor with just the FileName as argument or you can call the open() method with only the name of the file. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::btnSaveClick(TObject *Sender)
{
	char FirstName[30], LastName[30];
	int Age;

	strcpy(FirstName, edtFirstName->Text.c_str());
	strcpy(LastName, edtLastName->Text.c_str());
	Age = edtAge->Text.ToInt();

	if( SaveDialog1->Execute() )
	{
		ofstream Students;
		Students.open(SaveDialog1->FileName.c_str());
		Students << FirstName << "\n" << LastName << "\n" << Age;
	}
}
//---------------------------------------------------------------------------

After using a file, you should close it. This is taken care by using the ofstream::close() method whose syntax is:

void close();

Practical Learning Practical Learning: Saving a File

  1. Open the BodyTag1 application you created in the previous lessons. If you do not have it, open the BodyTag2 project from the exercises that accompany this book
  2. Display the main form, frmMain. From the Dialogs tab of the Tool Palette, double-click the SaveDialog button
  3. While the SaveDialog button is still selected on the form, on the Object Inspector, change the DefaultExt to btd
  4. In the FileName field, type Untitled
  5. In the Filter box, type
    Body Tag Documents (*.btd)|*.btd|Text Files (*.txt)|*.txt|All Files|*.*
  6. In the Title box, type Save Current Format Tag
  7. From the Additional tab of the Tool Palette, double-click the BitBtn button
  8. Set its Glyph as the Floppy1 bitmap from the Bitmaps folder that accompanies this ebook
  9. Change the button’s Name to btnSave and change its Caption to &Save…
     
  10. Double-click the new Save button to access its OnClick() event
  11. On the top section of the source file, include the fstream library:
     
    //---------------------------------------------------------------------------
    #include <vcl.h>
    #include <fstream>
    using namespace std;
    #pragma hdrstop
  12. Implement the new event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::btnSaveClick(TObject *Sender)
    {
    	DWORD RedBG, GreenBG, BlueBG,
    	RedText, GreenText, BlueText,
    	RedLink, GreenLink, BlueLink,
    	RedALink, GreenALink, BlueALink,
    	RedVLink, GreenVLink, BlueVLink;
    
    	RedBG = GetRValue(mmoPreview->Color);
    	GreenBG = GetGValue(mmoPreview->Color);
    	BlueBG = GetBValue(mmoPreview->Color);
    
    	RedText = GetRValue(edtPreviewText->Font->Color);
    	GreenText = GetGValue(edtPreviewText->Font->Color);
    	BlueText = GetBValue(edtPreviewText->Font->Color);
    
    	RedLink = GetRValue(edtPreviewLink->Font->Color);
    	GreenLink = GetGValue(edtPreviewLink->Font->Color);
    	BlueLink = GetBValue(edtPreviewLink->Font->Color);
    
    	RedALink = GetRValue(edtPreviewALink->Font->Color);
    	GreenALink = GetGValue(edtPreviewALink->Font->Color);
    	BlueALink = GetBValue(edtPreviewALink->Font->Color);
    
    	RedVLink = GetRValue(edtPreviewVLink->Font->Color);
    	GreenVLink = GetGValue(edtPreviewVLink->Font->Color);
    	BlueVLink = GetBValue(edtPreviewVLink->Font->Color);
    
    	if( SaveDialog1->Execute() )
    	{
    	    ofstream FormatToSave(SaveDialog1->FileName.c_str(), ios::out);
    	    if( !FormatToSave )
    	    {
    		ShowMessage("There was a problem saving the file.");
    		return;
    	    }
    
    	    Caption = "HTML Body Tag Formatter - " +
    	    ExtractFileName(SaveDialog1->FileName);
    
    	    FormatToSave << RedBG << "\n" << GreenBG << "\n"
    			 << BlueBG << "\n" << RedText << "\n"
    			 << GreenText << "\n" << BlueText << "\n"
    			 << RedLink << "\n" << GreenLink << "\n"
    			 << BlueLink << "\n" << RedALink << "\n"
    			 << GreenALink << "\n" << BlueALink << "\n"
    			 << RedVLink << "\n" << GreenVLink << "\n"
    			 << BlueVLink << "\n";
    
    	    FormatToSave.close();
    	}
    }
    //---------------------------------------------------------------------------
  13. Press F9 to test the application
  14. To test it, change the colors of the attributes (Background, Text, Link, Active Link, and Visited Link). Then click Save and set the name to Firmament
  15. Close the application and return to Borland C++ Builder
  16. Save All

Opening a File

Besides saving, another operation you can perform consists of opening an already existing file to have access to its contents. To do this, C++ provides the ifstream class. Like ofstream, the ifstream class provides various constructors you can use, two of which are particularly important. If you have enough information about the file you want to open, you can use the following constructor:

ifstream(const char* FileName, int FileMode);

The first argument of the constructor, FileName, is a constant string that represents the file that you want to open. The FileMode argument is a natural number that follows the table of modes as we described above.

If necessary, you can also declare an empty instance of the ifstream class using the default constructor:

ifstream();

After declaring this constructor, you can use the ifstream::open() method to formally open the intended file. The syntax of the open() method is:

open( const char* FileName, int FileMode);

This method uses the same arguments as the above constructor. By default, when declaring an instance of the ifstream class, it is assumed that you want to open a file; that is, you want to use the FileMode attribute with a value of ios::in. Therefore, the second argument is already set to ios::in value. This allows you to call the open() method with just the FileName value.

After using the ifstream class, you can close it using the ifstream::close() method. Here is an example:

//---------------------------------------------------------------------------
#include <vcl.h>
#include <fstream>
using namespace std;
#pragma hdrstop

#include "Exercise.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnSaveClick(TObject *Sender)
{
	char FirstName[30], LastName[30];
	int Age;

	strcpy(FirstName, edtFirstName->Text.c_str());
	strcpy(LastName, edtLastName->Text.c_str());
	Age = edtAge->Text.ToInt();

	if( SaveDialog1->Execute() )
	{
		ofstream Students;
		Students.open(SaveDialog1->FileName.c_str());
		Students << FirstName << "\n" << LastName << "\n" << Age;
	}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnOpenClick(TObject *Sender)
{
	char FirstName[30], LastName[30];
	int Age;

	if( OpenDialog1->Execute() )
	{
		ifstream Students;
		Students.open(OpenDialog1->FileName.c_str());
		Students >> FirstName >> LastName >> Age;
        	Students.close();

		edtFirstName->Text = FirstName;
		edtLastName->Text = LastName;
		edtAge->Text = Age;
	}
}
//---------------------------------------------------------------------------

Practical Learning Practical Learning: Opening a File

  1. Display the main form, frmMain. From the Dialogs tab of the Tool Palette, double-click the OpenDialog button 
  2. While the OpenDialog button is still selected on the form, on the Object Inspector, change the DefaultExt to btd
  3. In the FileName field, type Untitled
  4. In the Filter box, type
    Body Tag Documents (*.btd)|*.btd|Text Files (*.txt)|*.txt|All Files|*.*
  5. In the Title box, type Open a Tag Format
  6. From the Additional tab of the Tool Palette, double-click the BitBtn button
  7. Set its Glyph as the Open1 bitmap from the Bitmaps folder that accompanes this ebook
  8. Change the button’s Name to btnOpen and change its Caption to &Open…
     
  9. Double-click the Open button and implement its OnClick() event as follows:
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::btnOpenClick(TObject *Sender)
    {
    	DWORD RedBG, GreenBG, BlueBG,
    	RedText, GreenText, BlueText,
    	RedLink, GreenLink, BlueLink,
    	RedALink, GreenALink, BlueALink,
    	RedVLink, GreenVLink, BlueVLink;
    
    	ifstream FormatToOpen;
    
    	if( OpenDialog1->Execute() )
    	{
    		FormatToOpen.open(OpenDialog1->FileName.c_str(), ios::in);
    		if( !FormatToOpen )
    		{
    			ShowMessage("There was a problem opening the file.");
    			return;
    		}
    
    		Caption = "HTML Body Tag Formatter - " +
    		ExtractFileName(OpenDialog1->FileName);
    
    		FormatToOpen >> RedBG >> GreenBG >> BlueBG
    			     >> RedText >> GreenText >> BlueText
      			     >> RedLink >> GreenLink >> BlueLink
    			     >> RedALink >> GreenALink >> BlueALink
    			     >> RedVLink >> GreenVLink >> BlueVLink;
    
    		FormatToOpen.close();
    
    		scrRed->Position = 255 - RedBG;
    		scrGreen->Position = 255 - GreenBG;
    		scrBlue->Position = 255 - BlueBG;
    
    		edtNumRed->Text = RedBG;
    		edtNumGreen->Text = GreenBG;
    		edtNumBlue->Text = BlueBG;
    
    		edtHexaRed->Text = IntToHex(__int64(RedBG), 2);
    		edtHexaGreen->Text = IntToHex(__int64(GreenBG), 2);
    		edtHexaBlue->Text = IntToHex(__int64(BlueBG), 2);
    
    		edtBackground->Text = "#" +
    			AnsiString(IntToHex(__int64(RedBG), 2)) +
    			AnsiString(IntToHex(__int64(GreenBG), 2)) +
    			AnsiString(IntToHex(__int64(BlueBG), 2));
    		edtText->Text = "#" +
    			AnsiString(IntToHex(__int64(RedText), 2)) +
    			AnsiString(IntToHex(__int64(GreenText), 2)) +
    			AnsiString(IntToHex(__int64(BlueText), 2));
    		edtLink->Text = "#" +
    			AnsiString(IntToHex(__int64(RedLink), 2)) +
    			AnsiString(IntToHex(__int64(GreenLink), 2)) +
    			AnsiString(IntToHex(__int64(BlueLink), 2));
    		edtALink->Text = "#" +
    			AnsiString(IntToHex(__int64(RedALink), 2)) +
    			AnsiString(IntToHex(__int64(GreenALink), 2)) +
    			AnsiString(IntToHex(__int64(BlueALink), 2));
    		edtVLink->Text = "#" +
    			AnsiString(IntToHex(__int64(RedVLink), 2)) +
    			AnsiString(IntToHex(__int64(GreenVLink), 2)) +
    			AnsiString(IntToHex(__int64(BlueVLink), 2));
    
    		edtPreviewText->Font->Color = 
    				TColor(RGB(RedText, GreenText, BlueText));
    		edtPreviewLink->Font->Color = 
    				TColor(RGB(RedLink, GreenLink, BlueLink));
    		edtPreviewALink->Font->Color = 
    				TColor(RGB(RedALink, GreenALink, BlueALink));
    		edtPreviewVLink->Font->Color = 
    				TColor(RGB(RedVLink, GreenVLink, BlueVLink));
    
    		pnlPreview->Color = TColor(RGB(RedBG, GreenBG, BlueBG));
    		mmoPreview->Color = TColor(RGB(RedBG, GreenBG, BlueBG));
    		edtPreviewText->Color = TColor(RGB(RedBG, GreenBG, BlueBG));
    		edtPreviewLink->Color = TColor(RGB(RedBG, GreenBG, BlueBG));
    		edtPreviewALink->Color= TColor(RGB(RedBG, GreenBG, BlueBG));
    		edtPreviewVLink->Color= TColor(RGB(RedBG, GreenBG, BlueBG)); 
    		grpBodyAttributes->ItemIndex = 0;
    	}
    }
    //---------------------------------------------------------------------------
  10. Press F9 to test the application
  11. Open the previously saved format by clicking the Open... button
     
  12. After using the application, close it and return to Borland C++ Builder

VCL File Streaming

 

Introduction

The Visual Component Library (VCL) provides various built-in classes to perform file processing. Most of the features are provided through the TFileStream class. To perform file streaming using this class, first declare its instance using its constructor whose syntax is:

__fastcall TFileStream(const AnsiString FileName, Word Mode);

The first argument of this constructor is the name (or path) of the file you are dealing with. If the file does not exist or it cannot be accessed (opened or saved) for any reason, the compiler would throw an error and stop the action.

The second action, Mode, specifies what you are trying to do with the file.

The TFileStream class is conceptually designed to deal with the contents of one or more controls. Therefore, instead of concerning yourself with the values of controls, TFileStream would consider the change that affect a control on behalf of the user, which mostly is its contents. When saving a file, TFileStream faithfully gets the contents of all controls as you wish and saves them in one file. If opening a file, TFileStream locates the content of each file and restores it. Based on this, TFileStream is appropriate for VCL objects and usually its files should not mixed with non-VCL controls.

Saving Controls Contents

In order to save the contents of controls, first declare a pointer to TFileStream using its constructor and specify where the file would be saved. You can specify this path directly in the constructor if you know exactly where the file should be located. This can be done if you are writing a program that stores the default file at a specific location and you know where the file should be saved. Otherwise, you can use the SaveDialog control to let the user specify where to save the file.

When saving a file, the Mode argument of the constructor can be passed as one of the following constants:

Write Mode Description
fmCreate If the user is saving a new file, this is used to save it as new
fmOpenWrite This is used to save a file as new. If the file was previously saved and reopened, this mode would erase its previous contents and fill it with the new data
fmOpenReadWrite If the file already existed, this can be used to save a file that has been modified. Otherwise it can be used to create a new file

When it is possible that other people or application would try accessing the same file at the same time, the following constants can be used to manage the sharing of files:

Share Mode Description
fmShareExclusive Only the current application can access the file
fmShareDenyWrite The file can be opened by other applications but they cannot modify its contents
fmShareDenyRead The file can be modified by other applications but they cannot open it
fmShareDenyNone There is no restriction on what the other applications can do with the current file

To combine these two mode for the Mode argument, you use the bitwise OR operator |

Imagine you create a form equipped with a Memo and an Edit controls:

Here is an example of saving the contents of both controls to a file:

//---------------------------------------------------------------------------
void __fastcall TForm1::btnSaveClick(TObject *Sender)
{
	// Decalre a pointer to TFileStream
	TFileStream *FStream;

	// Let the user call the Save Dialog
	if( SaveDialog1->Execute() )
	{
		// Use the constructor of the TFileStream to create a file
		try {
			FStream = new TFileStream(SaveDialog1->FileName, fmCreate);
			// In the pointer to FStream, add the contents of the Memo
			FStream->WriteComponent(Memo1);
			// and the content of the Edit controls
			FStream->WriteComponent(Edit1);
		}
		__finally
		{
			// Since the pointer was created, delete it,
			// whether it was used or not
			delete FStream;
		}
	}
}
//---------------------------------------------------------------------------

Loading Controls Contents

When saving the contents of controls using TFileStream, the file is arranged so the class can locate data for each object. Based on this, you can use TFileStream to open a file that was created with this class. To do this, once again, declare a pointer to TFileStream and initialize the file using the constructor. If you already know where the file is located, you can simply provide it to the constructor. Otherwise, you can use the Open dialog box and let the user select the file.

When opening a file, you can use one of the following modes as the Mode argument:

Read Mode Description
fmOpenRead This is used to open a file but the user cannot modify and then save it.
fmOpenReadWrite This allows opening an existing file, modifying, and saving it.

You can combine this mode with one of the above share modes using the bitwise OR operator. Here is an example from the same above form design:

//---------------------------------------------------------------------------
void __fastcall TForm1::btnOpenClick(TObject *Sender)
{
	TFileStream *FStream;

	if( OpenDialog1->Execute() )
	{
		try {
			FStream = new TFileStream(OpenDialog1->FileName,
			fmOpenRead | fmShareExclusive);
			FStream->ReadComponent(Memo1);
			FStream->ReadComponent(Edit1);
		}
		__finally
		{
			delete FStream;
		}
	}
}
//---------------------------------------------------------------------------

VCL File Buffering

 

Introduction

The Visual Component Library supports another technique of file processing. Instead of saving the components as "streamable" objects, it gives you the option of saving the contents of controls. These contents are taken as data and not as VCL components. We will refer to this technique as file buffering.

To process the contents of controls as "streamable" values, the value of each object of the application is taken in its C/C++ context, as a variable created from known data types. The application itself is created like any other:

  

Values Buffering

To create a file, you can use the TFileStream class reviewed earlier, using the same rules. To write data to a file, you can call the TFileStream::WriteBuffer() method. Its syntax is:

void __fastcall WriteBuffer(const void *Buffer, int Count);

The WriteBuffer() method is used when you must let the compiler know the amount of memory space you want to use for a particular variable. It requires two arguments. The first, Buffer, is the value that needs to be saved. The Count parameter specifies the number of bytes that the value will need to the stored.

Here is an example:

//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnSaveClick(TObject *Sender)
{
	TFileStream *Streamer;
	char FullName[40];
	TDateTime DOB;
	Integer Gender;

	strcpy(FullName, edtFullName->Text.c_str());
	DOB = StrToDate(edtDOB->Text);
	Gender = cboGender->ItemIndex;

	if( SaveDialog1->Execute() )
	{
		try {
			Streamer = new TFileStream(SaveDialog1->FileName, fmCreate);
			Streamer->WriteBuffer(&FullName, 40);
			Streamer->WriteBuffer(&DOB, 40);
			Streamer->WriteBuffer(&Gender, 20);
		}
		__finally
		{
			delete Streamer;
		}
	}
}
//---------------------------------------------------------------------------

Value Reading

Data reading in this context is performed using the ReadBuffer() method of the TFileStream class. Its syntax is:

void __fastcall ReadBuffer(void *Buffer, int Count);

The ReadBuffer() method also requires two pieces of information. The Buffer parameter is the value that needs to be read. The Count parameter is used to specify the number of bytes that need to be read for the Buffer value.

Here is an example:

//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnOpenClick(TObject *Sender)
{
	TFileStream *Streamer;
	char FullName[40];
	TDateTime DOB;
	Integer Gender;

	if( OpenDialog1->Execute() )
	{
		try {
			Streamer = new TFileStream(OpenDialog1->FileName, fmOpenRead);
			edtFullName->Text.Delete(0, 40);
			edtDOB->Text.Delete(0, 40);
			cboGender->ItemIndex = 2;

			Streamer->ReadBuffer(&FullName, 40);
			Streamer->ReadBuffer(&DOB, 40);
			Streamer->ReadBuffer(&Gender, 20);

			edtFullName->Text = FullName;
			edtDOB->Text = DateToStr(DOB);
			cboGender->ItemIndex = StrToInt(Gender);
		}
		__finally
		{
			delete Streamer;
		}
	}
}
//---------------------------------------------------------------------------

Win32 File Processing

 

File Creation

In your VCL applications, even on console applications created on the Microsoft Windows operating system, besides the C, the C++, and the VCL means of saving and opening files, the Win32 library provides its mechanism of file processing.

In order to use a file, you must obtain a handle for it. You can obtain a file handle by calling the CreateFile() function. Its syntax is:

HANDLE CreateFile(
	LPCTSTR lpFileName,
	DWORD dwDesiredAccess,
	DWORD dwShareMode,
	LPSECURITY_ATTRIBUTES lpSecurityAttributes,
	DWORD dwCreationDisposition,
	DWORD dwFlagsAndAttributes,
	HANDLE hTemplateFile
);

The lpFileName argument is a null-terminated string that represents the name of the file. You can explicitly specify it as a double-quoted string. If you want the user to save the current file or to open an existing file by the user specifying the name of the file, you can use an OpenDialog or a SaveDialog objects. In this case the lpFileName can be obtained with the TOpenDialog::FileName or the TSaveDialog::FileName member variables.

The dwDesiredAccess argument specifies the type of operation that will be performed on the file. It can have one or a combination of the following values:

  • 0: Information about a device (floppy, CD, DVD, hard disk, etc) will be retrieved without a file being accessed
  • DELETE: The file can be deleted
  • READ_CONTROL: The read rights of the file can be accessed or read from
  • STANDARD_RIGHTS_EXECUTE: Same as READ_CONTROL
  • STANDARD_RIGHTS_READ: Same as READ_CONTROL
  • STANDARD_RIGHTS_WRITE: Same as READ_CONTROL
  • SYNCHRONIZE: The file can be synchronized
  • WRITE_DAC: The discretionary access control list (DACL) can be modified
  • WRITE_OWNER: The owner of the file can be changed
  • FILE_EXECUTE: The file can be executed. For example, if the file being accessed is an application, it can be launched
  • FILE_READ_DATA: The data of the file can be read from
  • FILE_WRITE_DATA: Data can be written to the file
  • FILE_APPEND_DATA: data can be added to end of the file
  • FILE_READ_ATTRIBUTES: The attributes of the file can be accessed or viewed
  • FILE_READ_EA: The extended attributes of the file can be read from
  • FILE_WRITE_ATTRIBUTES: The attributes of the file can be modified
  • FILE_WRITE_EA: The extended attributes of the file can be written to
  • STANDARD_RIGHTS_READ: The read rights of the file can be read
  • STANDARD_RIGHTS_WRITE: The write rights of the file can be modified

Omitting the 0 value, the above flags can be combined using the bitwise OR operator. Alternatively, you can pass one of the following values for a combination of flags:

  • STANDARD_RIGHTS_REQUIRED: Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER 
  • STANDARD_RIGHTS_ALL: Combines DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, and SYNCHRONIZE
  • FILE_ALL_ACCESS: The user will be able to perform any allowed operation on the file
  • GENERIC_EXECUTE: combines FILE_READ_ATRIBUTES, STANDARD_RIGHTS_EXECUTE, and SYNCHRONIZE
  • GENERIC_READ: combines FILE_READ_ATRIBUTES, FILE_READ_DATA, FILE_READ_EA, STANDARD_RIGHTS_READ, and SYNCHRONIZE
  • GENERIC_WRITE: combines FILE_APPEND_DATA, FILE_WRITE_ATRIBUTES, FILE_WRITE_DATA, FILE_WRITE_EA, STANDARD_RIGHTS_WRITE, and SYNCHRONIZE

The dwShareMode argument controls how the file can be shared. Its possible values are:

  • 0: The file will not be shared
  • FILE_SHARE_DELETE: (Available only on Windows NT and 2000) The file can be shared and accessed by more than one user. Also, a user can request to delete it. If a user attempts to delete this file, his or her access rights will be checked
  • FILE_SHARE_READ: The file can be accessed only if the user is allowed to read from it
  • FILE_SHARE_WRITE: The file can be accessed only if the user is allowed to write to it

The lpSecurityAttributes argument specifies some security attributes used when creating the file. Such attributes are defined as SECURITY_ATTRIBUTES value. You can pass this argument as NULL, in which case the security attributes would be ignored.

The dwCreationDisposition argument specifies the behavior to adopt whether the file already exists or is just being created. It can have one of the following values:

  • CREATE_ALWAYS: If the file does not exist, it will be created. If the file exists already, it will be destroyed and replaced by a new one with an attribute of Archive
  • CREATE_NEW: If the file does not exist, it will be created. If the file already exists, the CreateFile() function would fail
  • OPEN_ALWAYS: If the file does not exist, it will be created. If the file already exists, it would be opened
  • OPEN_EXISTING: If the file does not exist, the CreateFile() function would fail. If the file already exists, it would be opened
  • TRUNCATE_EXISTING: If the file does not exist, the CreateFile() function would fail. If the file already exists, it must be opened with a GENERIC_WRITE dwDesiredAccess flag and subsequently, its size would be reduced to 0 bytes

The dwFlagsAndAtributes argument specifies the attribute(s) to apply to the file. It can have one or a combination of the following values:

  • FILE_ATTRIBUTE_ARCHIVE: The file will be marked as Archive
  • FILE_ATTRIBUTE_ENCRYPTED: The file will be encrypted
  • FILE_ATTRIBUTE_HIDDEN: The file will be marked as Hidden and consequently cannot display in Windows Explorer, My Computer, or any file viewing tool
  • FILE_ATTRIBUTE_NORMAL: The flag must be used by itself and means that the file has ordinary attributes
  • FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: The file will not be indexed
  • FILE_ATTRIBUTE_OFFLINE: The file will be accessed offline
  • FILE_ATTRIBUTE_READONLY: The file will be marked as Read-Only. Users can open and read its contents but cannot modify or delete it
  • FILE_ATTRIBUTE_SYSTEM: The file is part of the operating system
  • FILE_ATTRIBUTE_TEMPORARY: The file will be marked as a temporary object

The above attributes can also be combined with the following values:

  • FILE_FLAG_BACKUP_SEMANTICS
  • FILE_FLAG_DELETE_ON_CLOSE
  • FILE_FLAG_NO_BUFFERING
  • FILE_FLAG_OPEN_NO_RECALL
  • FILE_FLAG_OPEN_REPARSE_POINT
  • FILE_FLAG_OVERLAPPED
  • FILE_FLAG_POSIX_SEMANTICS
  • FILE_FLAG_RANDOM_ACCESS
  • FILE_FLAG_SEQUENTIAL_SCAN
  • FILE_FLAG_WRITE_THROUGH

The hTemplateFile argument is a handle to a template file. If you do not have or cannot use a file template (for example they are not supported on home operating systems), pass this argument as NULL.

If the CreateFile() function succeeds, it returns a handle to the file and you can use it as you see fit, to analyze it, to read its contents if allowed, or to write data to it if permitted. If this function fails, it returns INVALID_HANDLE_VALUE.

Practical Learning Practical Learning: Processing Files with Win32

  1. Start a new application with its default form
  2. To save it, on the Standard toolbar, click the Save button
  3. Locate your exercises folder and display it in the Save In combo box
  4. Click the Create New Folder button. Type FastFood3 and press Enter twice to display it in the Save In combo box
  5. Save the unit as Exercise and the project as FastFood3
  6. Design the form as follows:
     
    Control Name Caption/Text Other Properties
    Bevel      
    Label   Processed By:  
    Edit edtProcessedBy    
    Label   Order Date:  
    MaskEdit     EditMask: !99/99/0000;1;_
    GroupBox GroupBox   Bread  
    RadioButton RadioButton rdoBun B&un Alignment: taLeftJustify
    RadioButton RadioButton rdoRoll &Roll Alignment: taLeftJustify
    GroupBox GroupBox   Ingredients  
    CheckBox CheckBox chkRegulars Re&gulars Alignment: taLeftJustify
    CheckBox CheckBox chkSweetener S&weetener Alignment: taLeftJustify
    Checked: true
    CheckBox CheckBox chkCheese Ch&eese Alignment: taLeftJustify
    CheckBox CheckBox chkBacon B&acon Alignment: taLeftJustify
    GroupBox GroupBox   Options  
    BitBtn btnIngredients &Ingredients  
    RadioButton RadioButton rdoMayonnaise &Mayonnaise Alignment: taLeftJustify
    RadioButton RadioButton rdoKetchup &Ketchup Alignment: taLeftJustify
    RadioButton RadioButton rdoMustard Mus&tard Alignment: taLeftJustify
    BitBtn     Kind: bkClose
    Label   Total Price:  
    Edit edtTotalPrice $2.35  
    Bevel      
    BitBtn btnSave &Save  
    BitBtn btnOpen &Open  
  7. In the header file of the form, create a structure called TCustomerOrder and declare its instance in the private section of the form’s class:
     
    //---------------------------------------------------------------------------
    struct TCustomerOrder
    {
    	char strClerk[20];
    	TDateTime dteOrderDate;
    	Integer iBread;
    	Integer iMeat;
    	Boolean bLettuce;
    	Boolean bOnion;
    	Boolean bTomato;
    	Boolean bPickles;
    	Integer iIngredients;
    	Boolean bCheese;
    	Boolean bBacon;
    };
    //---------------------------------------------------------------------------
    class TfrmMain : public TForm
    {
    __published: // IDE-managed Components
    
    . . .
    
    private:
    	void __fastcall EvaluatePrice();
    	TCustomerOrder CustOrder; // User declarations
    public: // User declarations
    	__fastcall TfrmMain(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
  8. Save all
  9. To add another form, on the main menu, click File -> New -> Form
  10. Design the form as follows
     
    Control Name Caption/Text Other Properties
    Bevel      
    CheckBox chkLettuce &Lettuce Alignment: taLeftJustify
    CheckBox chkOnion &Onion Alignment: taLeftJustify
    CheckBox chkTomato &Tomato Alignment: taLeftJustify
    CheckBox chkPickles &Pickles Alignment: taLeftJustify
    Button   OK ModalResult: mrOk
    Button   Cancel ModalResult: mrCancel
    Form     Ingredients BorderStyle: bsDialog
    Position: poScreenCenter
  11. Save the unit as Ingredients

File Saving

As its name suggests, the CreateFile() function is used to create a stream. Actually, it initiates a file object. After calling, since it returns a file handle, your next action is to decide what to do with this handle and one of the actions you can take is to store a newly created file into a drive.

To save a file in Win32, you can call the WriteFile() function. Of course, in order to save a file, you must first retrieve the value to be saved. This value can be made of a single variable or a complex class. Therefore, you must know what the value to save is made of because it must be supplied to the WriteFile() function. The syntax of this function is:

BOOL WriteFile(HANDLE hFile,
               LPCVOID lpBuffer,
               DWORD nNumberOfBytesToWrite,
               LPDWORD lpNumberOfBytesWritten,
               LPOVERLAPPED lpOverlapped);

The hFile argument is the handle to the file. It is typically the return value of a call to the CreateFile() function. Since in this case we are trying to save a file, the file should/must have been created with at least the GENERIC_WRITE flag for the dwDesiredAccess argument of the CreateFile() function.

The lpBuffer argument is the object that will be saved. As you can see, it is defined as a pointer to VOID, meaning that its type is not known in advance, which leaves it up to you to decide what type of value is being saved. It can be a C/C++ generic type (integer, character, floating-point value, or their variants). It can be a VCL or a Win32 type of object. It can also be a completely new type that you create as a simple C structure or a more elaborate C++, VCL, or Win32 class.

The nNumberOfBytesToWrite argument is the number of bytes to save. As the DWORD type indicates, it must be a positive integer.

The lpNumberOfBytesWritten argument is a positive integer returned by the function as the number of bytes that were written.

The lpOverlapped argument is necessary only if the file was created with the FILE_FLAG_OVERLAPPED flag for the dwFlagsAndAtributes argument of the CreateFile() function.

Practical Learning Practical Learning: Saving a File

  1. From the Dialogs tab of the Tool Palette, click the SaveDialog button and click on the form
  2. Change its properties as follows:
    DefaultExt: fst
    Filter: Fast Food Files (*.fst)|*.fst|Text Files (*.txt)|*.txt|All Files
    Title: Save Customer's Order
  3. On the form, double-click the Save button and implement its OnClick() event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::btnSaveClick(TObject *Sender)
    {
    	HANDLE hFile;
    	DWORD dFileSize, dBytesWritten;
    	BOOL bResult;
    
    	if( SaveDialog1->Execute() )
    	{
    		__try {
    			hFile = CreateFile(SaveDialog1->FileName.c_str(),
    			GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
    			FILE_FLAG_RANDOM_ACCESS, NULL);
    
    			if( hFile == INVALID_HANDLE_VALUE )
    			{
    		ShowMessage("There was a problem saving the customer order");
    				return;
    			}
    
    			dFileSize = sizeof(CustOrder);
    
    			if( dFileSize == 0xFFFFFFFF )
    			{
    				ShowMessage("Invalid file size");
    				return;
    			}
    
    			strcpy(CustOrder.strClerk, edtClerk->Text.c_str());
    			CustOrder.dteOrderDate = edtOrderDate->Text;
    
    			if( rdoBun->Checked )
    				CustOrder.iBread = 0;
    			else if( rdoRoll->Checked )
    				CustOrder.iBread = 1;
    			if( rdoBeefPatty->Checked )
    				CustOrder.iMeat = 0;
    			else if( rdoGrilledChicken->Checked )
    				CustOrder.iMeat = 1;
    			else if( rdoChickenBreast->Checked )
    				CustOrder.iMeat = 2;
    
    		CustOrder.bLettuce = dlgIngredients->chkLettuce->Checked;
    		CustOrder.bOnion = dlgIngredients->chkOnion->Checked;
    		CustOrder.bTomato = dlgIngredients->chkTomato->Checked;
    		CustOrder.bPickles = dlgIngredients->chkPickles->Checked;
    
    			CustOrder.bCheese = chkCheese->Checked;
    			CustOrder.bBacon = chkBacon->Checked;
    
    			if( rdoMayonnaise->Checked )
    				CustOrder.iIngredients = 0;
    			else if( rdoKetchup->Checked )
    				CustOrder.iIngredients = 1;
    			else if( rdoMustard->Checked )
    				CustOrder.iIngredients = 2;
    
    			bResult = WriteFile( hFile, &CustOrder, dFileSize,
    						&dBytesWritten, NULL );
    
    			if( bResult == FALSE )
    			{
    				ShowMessage("The file could not be saved");
    				return;
    			}
    		}
    		__finally
    		{
    			if( hFile != INVALID_HANDLE_VALUE )
    				CloseHandle(hFile);
    		}
    	}
    }
    //---------------------------------------------------------------------------
  4. Test the application with a customer order and save it
     
  5. Close the form and return to Borland C++ Builder
  6. Save All

File Opening

Besides saving a file, another operation you can perform on streams using the Win32 approach is to open an existing file. Reading a file is performed sing the ReadFile() function. Its syntax is:

BOOL ReadFile(HANDLE hFile,
              LPVOID lpBuffer,
              DWORD nNumberOfBytesToRead,
              LPDWORD lpNumberOfBytesRead,
              LPOVERLAPPED lpOverlapped);

The hFile parameter is a handle to the file to be opened. It can be the return value of a previous call to the CreateFile() function.

The lpBuffer parameter is the object or value to be opened. As its type suggests, it can be anything and it is up to you to define what type of value is being opened.

The nNumberOfBytesToRead parameter is the number of bytes to read.

The lpNumberOfBytesRead parameter is a returned value of the function, indicating the number of bytes that were read.

The lpOverlapped parameter is used if the file is being opened as “overlapped”, in which case the lpOverlapped argument of the CreateFile() function would have received the FILE_FLAG_OVERLAPPED flag.

Practical Learning Practical Learning: Opening a File

  1. Display the main form. From the Dialogs tab of the Tool Palette, click the OpenDialog button and click the form
  2. Change its properties as follows:
    DefaultExt: fst
    Filter: Fast Food Files (*.fst)|*.fst|Text Files (*.txt)|*.txt|All Files
    Title: Open a Previous Order

     
  3. On the form, double-click the Open button and implement its OnClick event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::btnOpenClick(TObject *Sender)
    {
    	HANDLE hFile;
    	DWORD dFileSize, dBytesRead;
    	BOOL bResult;
    
    	if( OpenDialog1->Execute() == True )
    	{
    		__try {
    	hFile = CreateFile(OpenDialog1->FileName.c_str(), GENERIC_READ,
    				0, NULL, OPEN_EXISTING,
    				FILE_ATTRIBUTE_NORMAL, NULL);
    			if( hFile == INVALID_HANDLE_VALUE )
    			{
    			ShowMessage("There was a problem opening the file");
    				return;
    			}
    
    			dFileSize = GetFileSize(hFile, NULL);
    			if( dFileSize == 0xFFFFFFFF )
    			{
    				ShowMessage("Invalid file size");
    				return;
    			}
    
    	bResult = ReadFile(hFile, &CustOrder, dFileSize, &dBytesRead, NULL);
    
    			if( bResult == FALSE )
    			{
    				ShowMessage("The file could not be read");
    				return;
    			}
    
    			edtClerk->Text = CustOrder.strClerk;
    			edtOrderDate->Text = CustOrder.dteOrderDate;
    			if( CustOrder.iBread == 0 )
    				rdoBun->Checked = True;
    			else if( CustOrder.iBread == 1 )
    				rdoRoll->Checked = True;
    
    			if( CustOrder.iMeat == 0 )
    				rdoBeefPatty->Checked = True;
    			else if( CustOrder.iMeat == 1 )
    				rdoGrilledChicken->Checked = True;
    			else if( CustOrder.iMeat == 2 )
    				rdoChickenBreast->Checked = True;
    
    			bLettuce = CustOrder.bLettuce;
    			bOnion = CustOrder.bOnion;
    			bTomato = CustOrder.bTomato;
    			bPickles = CustOrder.bPickles;
    
    			if( (bLettuce == False) &&
    			    (bOnion == False) &&
    			    (bTomato == False) &&
    			    (bPickles == False) )
    				chkRegulars->State = cbUnchecked;
    			else if( (bLettuce == True) &&
    				 (bOnion == True) &&
    				 (bTomato == True) &&
    				 (bPickles == True) )
    				chkRegulars->State = cbChecked;
    			else
    				chkRegulars->State = cbGrayed;
    
    			chkCheese->Checked = CustOrder.bCheese;
    			chkBacon->Checked = CustOrder.bBacon;
    			if( CustOrder.iIngredients == 0 )
    				rdoMayonnaise->Checked = True;
    			else if( CustOrder.iIngredients == 1 )
    				rdoKetchup->Checked = True;
    			else if( CustOrder.iIngredients == 2 )
    				rdoMustard->Checked = True;
    
    			chkSweetenerClick(Sender);
    			EvaluatePrice();
    		}
    		__finally
    		{
    			if( hFile != INVALID_HANDLE_VALUE )
    				CloseHandle(hFile);
    		}
    	}
    }
    //---------------------------------------------------------------------------
  4. Test the application and open the previous order saved to file
  5. After using the form, close it and return to Borland C++ Builder
  6. Save All
Previous Copyright © 2004-2007 Yevol Next