Overview of File Processing and Definitions
|
Introduction
|
In Lesson 3, we saw that a piece
of information used in an application was primarily represented as a group of
bits. So far, if we requested information from the user, when the application
exited, we lost all information that the user had entered. This is because such
information was only temporarily stored in the random access memory (RAM). In
some cases, you will want to "keep" information that the user has
entered so you can make the information available the next time the user opens
the application. In some other cases, whether you request information from the
user or inherently provide it to the user, you may want different people working
from different computers to use or share the same data. In these and other
scenarios, you must store the information somewhere and retrieve it
when necessary. This is the basis of file processing.
Files
|
A file is a series of bytes of data that are arranged in a
particular manner to produce a usable document. For easy storage, location, and
management, the bytes are stored on a medium such as a hard disc, a floppy disc,
a compact disc, or any valid and supported type of storage. When these bytes belong
to a single but common entity and hold values that are stored on a medium, the
group is referred to as a file.
For greater management, files can be stored
in a parent object called a directory or a folder. Since a file is a unit of
storage and it stores information, it has a size, which is the number of bits it
uses to store its values. To manage it, a file has a location also called a path
that specifies where and/or how the file can be retrieved. Also, for better
management, a file has attributes (characteristics) that indicate what can be done on the file or
that provide specific information that the programmer or the operating system can
use when dealing with the file.
Streams
|
File processing consists of creating, storing, and/or retrieving
the contents of a file from a recognizable medium. For example, it is used to save
word-processed files to a hard drive, to store a presentation on floppy disk, or to
open a file from a CD-ROM. A stream is the technique or means of performing file
processing. In order to manage files stored in a computer, each file must be able to
provide basic pieces of information about itself. This basic information is specified
when the file is created but can change during the lifetime of a file.
To create a file, a user must first decide where it
would be
located: this is a requirement. A file can be located on the root drive.
Alternatively,
a file can be positioned inside of an existing folder. Based on security
settings, a user may not be able to create a file just anywhere in the
(file system of the) computer. Once the user has decided where the file
would reside, there are various means of creating files that the users
are trained to use. When creating a file, the user must give it a name
following the rules of the operating system combined with those of the
file system.
The most fundamental piece of information a file must have is a name.
Once the user has created a file, whether the file
is empty or not, the operating system assigns basic pieces of
information to it. Once a file is created, it can be opened, updated,
modified, renamed, etc.
Streaming Prerequisites
|
Introduction
|
To support file processing, the .NET Framework provides the System::IO
namespace that contains many different classes to handle almost any type of file
operation you may need to perform.
Therefore, to perform file processing, you
can include the System::IO namespace in your project.
The parent class of file processing is Stream. With Stream, you can store data
to a stream or you can retrieve data from a stream.
Stream is an abstract class, which means that you cannot use it to declare a
variable in your
application. As an abstract class, Stream is used as the parent of the
classes that actually implement the necessary operations. You will usually use a
combination of classes to perform a typical operation. For example, some classes
are used to create a stream object while some others are used to write data to
the created stream.
- Start Microsoft Visual C++ and create a new CLR Console Application named IceCream3
- Change the file as follows:
// IceCream3.cpp : main project file. #include "stdafx.h" using namespace System; // This class is used to create and manage an ice scream // and to process an order public ref class CIceCream sealed { public: // This is the base price of an ice scream // Optional values may be added to it static const double BasePrice = 1.55; // These arrays are used to build the components // of various ice screams private: array<String ^> ^ Flavor; array<String ^> ^ Container; array<String ^> ^ Ingredient; // Additional factor used to process an ice scream order int Scoops; double TotalPrice; // Variables that will hold the user's choice // These are declared "globally" so they can be // shared among methods int ChoiceFlavor; int ChoiceContainer; int ChoiceIngredient; // This default constructor is the best place for // us to initialize the array public: CIceCream() { Flavor = gcnew array<String ^>(10); Flavor[0] = L"Vanilla"; Flavor[1] = L"Cream of Cocoa"; Flavor[2] = L"Chocolate Chip"; Flavor[3] = L"Organic Strawberry"; Flavor[4] = L"Butter Pecan"; Flavor[5] = L"Cherry Coke"; Flavor[6] = L"Chocolate Brownies"; Flavor[7] = L"Caramel Au Lait"; Flavor[8] = L"Chunky Butter"; Flavor[9] = L"Chocolate Cookie"; Ingredient = gcnew array<String^>(4); Ingredient[0] = L"No Ingredient"; Ingredient[1] = L"Peanuts"; Ingredient[2] = L"M & M"; Ingredient[3] = L"Cookies"; Container = gcnew array<String^>(3); Container[0] = L"Cone"; Container[1] = L"Cup"; Container[2] = L"Bowl"; } // This method requests a flavor from the user and // returns the choice void ChooseFlavor() { // Make sure the user selects a valid number //that represents a flavor... do { // In case the user types a symbol that // is not a number try { Console::WriteLine(L"What type of flavor do you want?"); for (int i = 0; i < Flavor->Length; i++) Console::WriteLine(L"{0} - {1}", i + 1, Flavor[i]); Console::Write(L"Your Choice? "); ChoiceFlavor = int::Parse(Console::ReadLine()); } catch(FormatException ^) // display an appropriate message { Console::WriteLine(L"You must enter a valid number " L"and no other character!"); } // If the user typed an invalid number out of the // allowed range // let him or her know and provide another chance if( ChoiceFlavor < 1 || ChoiceFlavor > Flavor->Length) Console::WriteLine(L"Invalid Choice - Try Again!\n"); } while (ChoiceFlavor < 1 || ChoiceFlavor > Flavor->Length); } // This method allows the user to select a container void ChooseContainer() { // Make sure the user selects a valid number that // represents a container do { // If the user types a symbol that is not a number try { Console::WriteLine(L"What type of container do you want?"); for (int i = 0; i < Container->Length; i++) Console::WriteLine(L"{0} - {1}", i + 1, Container[i]); Console::Write(L"Your Choice? "); ChoiceContainer = int::Parse(Console::ReadLine()); } catch (FormatException ^) // display an appropriate message { Console::WriteLine(L"You must enter a valid " L"number and no other character!"); } // If the user typed an invalid number out of the // allowed range // let him or her know and provide another chance if( (ChoiceContainer < 1) || (ChoiceContainer > Container->Length) ) Console::WriteLine(L"Invalid Choice - Try Again!"); } while ((ChoiceContainer < 1) || (ChoiceContainer > Container->Length)); } void ChooseIngredient() { do { try { Console::WriteLine(L"Do you want an ingredient or not"); for (int i = 0; i < Ingredient->Length; i++) Console::WriteLine(L"{0} - {1}", i + 1, Ingredient[i]); Console::Write(L"Your Choice? "); ChoiceIngredient = int::Parse(Console::ReadLine()); } catch (FormatException ^) { Console::WriteLine(L"You must enter a valid " L"number and no other character!"); } if( (ChoiceIngredient < 1) || (ChoiceIngredient > Ingredient->Length) ) Console::WriteLine(L"Invalid Choice - Try Again!"); } while ((ChoiceIngredient < 1) || (ChoiceIngredient > Ingredient->Length)); } void SpecifyNumberOfScoops() { do { try { Console::Write(L"How many scoops(1, 2, or 3)? "); Scoops = int::Parse(Console::ReadLine()); } catch (FormatException ^) { Console::WriteLine(L"You must enter a valid number " L"and no other character!"); } if( Scoops < 1 || Scoops > 3 ) Console::WriteLine(L"Invalid Choice - Try Again!"); } while (Scoops < 1 || Scoops > 3); } // This method is used to process a customer order // It uses the values of the above methods void ProcessAnOrder() { double PriceIngredient, PriceScoop; // Let the user know that this is a vending machine Console::WriteLine(L"=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*="); Console::WriteLine(L"Ice Scream Vending Machine"); Console::WriteLine(L"-----------------------------------"); // Let the user select the components of the ice scream ChooseFlavor(); Console::WriteLine(L"-----------------------------------"); ChooseContainer(); Console::WriteLine(L"-----------------------------------"); ChooseIngredient(); Console::WriteLine(L"-----------------------------------"); SpecifyNumberOfScoops(); Console::WriteLine(L"-----------------------------------"); // If the user selects an ingredient instead of "No Ingredient", // add $0.50 to the order if( (ChoiceIngredient == 2) || (ChoiceIngredient == 3) || (ChoiceIngredient == 4) ) PriceIngredient = 0.50; else PriceIngredient = 0.00; // Instead of multiplying a number scoops to a value, // We will use an incremental value depending on // the number of scoops if( Scoops == 1 ) PriceScoop = 0.65; else if( Scoops == 2 ) PriceScoop = 1.05; else PriceScoop = 1.55; // Calculate the total price of the ice scream TotalPrice = BasePrice + PriceScoop + PriceIngredient; // Create the ice scream... // And display a receipt to the user DisplayReceipt(); } // This method is used to display a receipt to the user void DisplayReceipt() { Console::WriteLine(L"\n=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*="); Console::WriteLine(L"Ice Scream Order"); Console::WriteLine(L"-----------------------------------"); Console::WriteLine(L"Flavor: {0}", Flavor[ChoiceFlavor - 1]); Console::WriteLine(L"Container: {0}", Container[ChoiceContainer - 1]); Console::WriteLine(L"Ingredient: {0}", Ingredient[ChoiceIngredient - 1]); Console::WriteLine(L"Scoops: {0}", Scoops); Console::WriteLine(L"Total Price: {0:C}", TotalPrice); Console::WriteLine(L"=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\n"); } }; int main(array<System::String ^> ^args) { CIceCream ^ ic = gcnew CIceCream(); ic->ProcessAnOrder(); Console::WriteLine(); return 0; }
- Execute the project and test it. Here is an example:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Scream Vending Machine ----------------------------------- What type of flavor do you want? 1 - Vanilla 2 - Cream of Cocoa 3 - Chocolate Chip 4 - Organic Strawberry 5 - Butter Pecan 6 - Cherry Coke 7 - Chocolate Brownies 8 - Caramel Au Lait 9 - Chunky Butter 10 - Chocolate Cookie Your Choice? 3 ----------------------------------- What type of container do you want? 1 - Cone 2 - Cup 3 - Bowl Your Choice? 5 Invalid Choice - Try Again! What type of container do you want? 1 - Cone 2 - Cup 3 - Bowl Your Choice? 3 ----------------------------------- Do you want an ingredient or not 1 - No Ingredient 2 - Peanuts 3 - M & M 4 - Cookies Your Choice? 8 Invalid Choice - Try Again! Do you want an ingredient or not 1 - No Ingredient 2 - Peanuts 3 - M & M 4 - Cookies Your Choice? 4 ----------------------------------- How many scoops(1, 2, or 3)? 3 ----------------------------------- =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Scream Order ----------------------------------- Flavor: Chocolate Chip Container: Bowl Ingredient: Cookies Scoops: 3 Total Price: $3.60 =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Press any key to continue . . .
- Close the DOS window
The Name of a File
|
Before performing file processing, one of your early
decisions will consist of specifying the type of operation you want the user to perform.
For example, the user may want to create a brand new file, open an
existing file, or perform a routine operation on a file. In all
or most cases, whether you are creating a new file or manipulating an existing
one,
you must specify the name of the file. You can do this by declaring a String
variable but, as we will learn later on, most classes used to create a stream can
take a string that represents the file.
If you are creating a new file, there are certainly
some
rules you must observe. The name of a file follows the directives of the
operating system. On MS DOS and Windows
3.X (that is, prior to Microsoft Windows 9X), the file had to use the
8.3 format. The actual name had to have a maximum of 8 characters with
restrictions on the characters that could be used. The user also had to
specify three characters after a period. The three characters, known as
the file extension, were used by the operating system to classify the
file. That was all necessary for those 8-bit and 16-bit operating
systems.
Various rules have changed. For example, the names of folders and files
on Microsoft Windows >= 95 can have up to 255 characters. The
extension of the file is mostly left to the judgment of the programmer
but the files are still using extensions. Applications can also be
configured to save different types of files; that is, files with
different extensions.
At the time of this writing, the rules for file names for Microsoft Windows were on the MSDN web site at Windows Development\Windows Base Services\Files and I/O\SDK Documentation\Storage\Storage Overview\File Management\Creating, Deleting, and Maintaining Files\Naming a File (because it is a web site and not a book, its pages can change anytime). |
Based on this, if you declare a string variable to
hold the name of the file, you can simply initialize the variable with the
necessary name and its extension. Here is an example:
using namespace System;
int main()
{
String ^ NameOfFile = L"Employees.spr";
return 0;
}
- Access the IceCream.cs file and add a new public method named SaveOrder
of type void as follows:
// IceCream3.cpp : main project file. #include "stdafx.h" using namespace System; // This class is used to create and manage an ice scream // and to process an order public ref class CIceCream sealed { . . . No Change // This method is used to display a receipt to the user void DisplayReceipt() { . . . No Change } void SaveOrder() { String ^ NameOfFile; Console::Write(L"Please enter your initials or the " L"name we will use to remember your order: "); NameOfFile = Console::ReadLine(); } }; int main(array<System::String ^> ^args) { char answer = L'n'; CIceCream ^ ic = gcnew CIceCream(); ic->ProcessAnOrder(); Console::Write(L"Do you want us to remember this " L"order the next time you come to " L"get your ice scream (y/n)? "); answer = char::Parse(Console::ReadLine()); if( answer == L'y' || answer == L'Y' ) ic->SaveOrder(); Console::WriteLine(); return 0; }
- Execute the project and test it
- Close the DOS window
The Path to a File
|
If you declare a string as above, the file will be
created in
the folder as the application. Otherwise, you can create your new file
anywhere
in the hard drive or on another medium. To do that, you must provide a
complete path where the file
will reside. A path is a string that specifies the drive (such as A:,
C:, or D:,
etc). The sections of
a complete path are separated by a backslash. For example, a path can be
made of a folder followed by the name of the file. An example would be
C:\Palermo.tde
A path can also consist of a drive followed by the name of
the folder in which the file will be created. Here is an example:
C:\Program Files\Palermo.tde
A path can also indicate that the file will be created in a
folder that itself is inside of another folder. In this case, remember that the
names of folders must be separated by backslashes.
In Lesson 2, we saw that the
backslash character is used to create or manage escape
sequences and it can be included in a string value to make up an escape
sequence. Because of this, every time you include a backslash in a string, the
compiler thinks that you are trying to provide an escape sequence. In this case,
if the combination of the backslash and the character that follows the backslash
is not recognized as an escape sequence, you would get an error. To solve this
problem, you have two alternatives. To indicate that the backslash must be
considered as a character in its own right, you can double it. Here are
examples:
int main() { String ^ NameOfFile = L"C:\\Documents and " L"Settings\\Business Records\\Employees.spr"; return 0; } }
In the same way, you can declare a String variable to
represent the name of an existing file that you plan to use in your program. You
can also represent its path.
When providing a path to the file, if the drive you specify
doesn't exist or cannot be read, the compiler would consider that the file
doesn't exist. If you provide folders that don't exist in the drive, the
compiler would consider that the file doesn't exist. This also means that the
compiler will not create the folder(s) (the .NET Framework provides all means to
create a folder but you must ask the compiler to create it; simply specifying a
folder that doesn't exist will not automatically create it, even if you are
creating a new file). Therefore, it is your responsibility to make sure that
either the file or the path to the file is valid. As we will see in the next
section, the compiler can check the existence of a file or path.
The .NET Support for Files
|
Introduction
|
The primary support of a file as an object is provided by a
.NET Framework class called File. This static class is equipped with
various types of (static) methods to create, save, open, copy, move, delete, or
check the existence of a file.
File Existence
|
One of the valuable operations that the File class can
perform is to check the existence of the file you want to use. For example, if
you are creating a new file, you may want to make sure it doesn't exist already
because if you try to create a file that exists already, the compiler may first
delete the old file before creating the new one. This could lead to
unpredictable result, especially because such a file is not sent to the Recycle
Bin. On the other hand, if you are trying to open a file, you should first make
sure the file exists, otherwise the compiler will not be able to open a file it
cannot find.
To check the existence of a file, the File class provides
the Exists method. Its syntax is:
public: static bool Exists(String ^path);
If you provide only the name of the file, the compiler would
check it in the folder of the application. If you provide the path to the file, the
compiler would check its drive, its folder(s) and the file itself. In both
cases, if the file exists, the method returns true. If the compiler cannot find
the file, the method returns false. It's important to know that if you provided
a complete path to the file, any slight mistake would produce a false result.
- Access the IceCream.cs file and change it as follows:
// IceCream3.cpp : main project file. #include "stdafx.h" using namespace System; using namespace System::IO; // This class is used to create and manage an ice scream // and to process an order public ref class CIceCream sealed { public: . . . No Change // This method is used to display a receipt to the user void DisplayReceipt() { . . . No Change } void SaveOrder() { String ^ NameOfFile; Console::Write(L"Please enter your initials or the " L"name we will use to remember your order: "); NameOfFile = Console::ReadLine(); if( File::Exists(NameOfFile) ) { char Answer; Console::WriteLine(L"The file you entered exists already."); Console::Write(L"Do you want to replace it(y/n)?" ); Answer = char::Parse(Console::ReadLine()); if( Answer == L'y' || Answer == L'Y' ) Console::WriteLine(L"The former order with the " L"same name will be replaced"); else if( Answer == L'n' || Answer == L'N' ) { Console::WriteLine(L"Please enter a name we will " L"use to remember this order: "); NameOfFile = Console::ReadLine(); } else Console::WriteLine(L"Invalid Answer - We will close"); return; } else Console::WriteLine(L"Great"); } void OpenOrder() { String ^ NameOfFile; Console::Write(L"Please enter the name you previously " L"gave to remember your order: "); NameOfFile = Console::ReadLine(); if( File::Exists(NameOfFile) ) Console::WriteLine(L"The file would have been opened"); else Console::WriteLine(L"The name you entered is not registered " L"in our previous orders"); } }; int main(array<System::String ^> ^args) { char answer = L'n'; CIceCream ^ ic = gcnew CIceCream(); ic->ProcessAnOrder(); Console::Write(L"Do you want us to remember this " L"order the next time you come to " L"get your ice scream (y/n)? "); answer = char::Parse(Console::ReadLine()); if( answer == L'y' || answer == L'Y' ) ic->SaveOrder(); else Console::WriteLine(L"It was nice serving you." L"\nCome Again!!!\n"); Console::WriteLine(); return 0; }
- Execute it
File Creation
|
Besides checking the existence of the file, the File
class can be used to create a new file. To support this operation, the File
class is equipped with the Create() method that is overloaded with two
versions as follows:
public: static FileStream ^ Create(String ^ path); public: static FileStream ^ Create(String ^ path, int buffersize);
In both cases, the File.Create() method returns a Stream
value, in this case a FileStream value. As the File.Create() method indicates, it takes the name or
path of the file as argument. If you know or want to specify the size, in bytes,
of the file, you can use the second version.
To provide the same operation of creating a file, you can
use the Open() method of the File class. It is overloaded in three
versions as follows:
public: static FileStream ^ Open(String ^ path, FileMode mode); public: static FileStream ^ Open(String ^ path, FileMode mode, FileAccess access); public: static FileStream Open(String ^ path, FileMode mode, FileAccess access, FileShare share);
Access to a File
|
In order to perform an operation on a file, you must specify
to the operating system how to proceed. One of the options you have is to
indicate the type of access that will be granted on the file. This access is
specified using the FileAccess enumerator. The members of the FileAccess
enumerator are:
- FileAccess::Write: New data can be written to the file
- FileAccess.Read: Existing data can be read from the file
- FileAccess.ReadWrite: Existing data can be read from the file and new data be written to the file
File Sharing
|
In standalone workstations, one person is usually able to
access and open a file then perform the necessary operations on it. In networked
computers, you may create a file that different people can access at the same
time or you may make one file access another file to retrieve information. For
example, suppose you create an application for a fast food restaurant that has
two or more connected workstations and all workstations save their customers
orders to a common file. In this case, you must make sure that any of the
computers can access the file to save an order. An employee from one of these
workstations must also be able to open the file to retrieve a customer order for
any necessary reason. You can also create a situation where one file holds an
inventory of the items of a store and another file holds the customers orders.
Obviously one file would depend on another. Based on this, when an operation
must be performed on a file, you may have to specify how a file can be shared.
This is done through the FileShare enumerator.
The values of the FileShare enumerator are:
- FileShare.Inheritable: Allows other file handles to inherit from this file
- FileShare.None: The file cannot be shared
- FileShare.Read: The file can be opened and read from
- FileShare::Write: The file can be opened and written to
- FileShare.ReadWrite: The file can be opened to write to it or read from it
The Mode of a File
|
Besides the access to the file, another option you will most
likely specify to the operating system is referred to as the mode of a file. It
is specified through the FileMode enumerator. The members of the FileMode
Enumerator are:
- FileMode.Append: If the file already exists, the new data will be added to its end. If the file doesn't exist, it will be created and the new data will be added to it
- FileMode.Create: If the file already exists, it will be deleted and a new file with the same name will be created. If the file doesn't exist, then it will be created
- FileMode.CreateNew: If the new already exists, the compiler will throw an error. If the file doesn't exist, it will be created
- FileMode.Open: If the file exists, it will be opened. If the file doesn't exist, an error would be thrown
- FileMode.OpenOrCreate: If the file already exists, it will be opened. If the file doesn't exist, it will be created
- FileMode.Truncate: If the file already exists, its contents will be deleted completely but the file will be kept, allowing you to write new data to it. If the file doesn't exist, an error would be thrown
Fundamentals of File Streaming
|
Introduction
|
File streaming consists of performing one of the routine
operations on a file, such as creating it or opening it. This basic operation
can be performed using a class called FileStream.
You can use a FileStream object to get a stream ready for
processing. As one of the most complete classes of file processing of the .NET
Framework, FileStream is equipped with all necessary properties and
methods. To use it, you must first declare a variable of it. The class is
equipped with nine constructors.
One of the constructors (the second) of the FileStream
class has the following syntax:
public: FileStream(String ^ path, FileMode mode);
This constructor takes as its first argument the name or the
file or its path. The second argument specifies the type of operation to perform
on the file. Here is an example:
using namespace System;
using namespace System::IO;
int main()
{
String ^ NameOfFile = L"Persons.spr";
FileStream ^ fstPersons = gcnew FileStream(NameOfFile,
FileMode::Create);
return 0;
}
- To create a new stream, change the SaveOrder()
method in the IceCream.cs file and as follows:
// IceCream3.cpp : main project file. #include "stdafx.h" using namespace System; using namespace System::IO; // This class is used to create and manage an ice scream // and to process an order public ref class CIceCream sealed { . . . No Change void SaveOrder() { String ^ NameOfFile; FileStream ^ stmIceCream = gcnew FileStream(NameOfFile, FileMode::Create); . . . No Change } void OpenOrder() { . . . No Change } }; int main(array<System::String ^> ^args) { . . . No Change Console::WriteLine(); return 0; }
- Save the file
Stream Writing
|
A streaming operation is typically used to create a stream.
Once the stream is ready, you can write data to it. The writing operation is
perform through various classes. One of these classes is BinaryWriter.
The BinaryWriter class can be used to write values of
primitive data types (char, int, float, double,
etc). To use a BinaryWriter value, you can first declare its variable. To do
this, you would use one of the class' three constructors. One of its
constructors (the second) has the following syntax:
public: BinaryWriter(Stream ^ output);
This constructor takes as argument a Stream value,
which could be a FileStream variable. Here is an example:
using namespace System;
using namespace System::IO;
int main()
{
String ^ NameOfFile = L"Persons.spr";
FileStream ^ fstPersons = gcnew FileStream(NameOfFile,
FileMode::Create);
BinaryWriter ^ wrtPersons = gcnew BinaryWriter(fstPersons);
return 0;
}
Most classes that are used to add values to a stream are
equipped with a method called Write. This is also the case for the BinaryWriter
class. This method takes as argument the value that must be written to the
stream. The method is overloaded so that there is a version for each primitive
data type. Here is an example that adds strings to a newly created file:
using namespace System; using namespace System::IO; int main() { String ^ NameOfFile = L"Persons.spr"; FileStream ^ fstPersons = gcnew FileStream(NameOfFile, FileMode::Create); BinaryWriter ^ wrtPersons = gcnew BinaryWriter(fstPersons); wrtPersons->Write(L"James Bloch"); wrtPersons->Write(L"Catherina Wallace"); wrtPersons->Write(L"Bruce Lamont"); wrtPersons->Write(L"Douglas Truth"); return 0; }
Stream Closing
|
When you use a stream, it requests resources from the
operating system and uses them while the stream is available. When you are not
using the stream anymore, you should free the resources and make them available
again to the operating system so that other services can use them. This is done
by closing the stream.
To close a stream, you can can call the Close() method of
the class(es) you were using. Here are examples:
using namespace System; using namespace System::IO; int main() { String ^ NameOfFile = L"Persons.spr"; FileStream ^ fstPersons = gcnew FileStream(NameOfFile, FileMode::Create); BinaryWriter ^ wrtPersons = gcnew BinaryWriter(fstPersons); wrtPersons->Write(L"James Bloch"); wrtPersons->Write(L"Catherina Wallace"); wrtPersons->Write(L"Bruce Lamont"); wrtPersons->Write(L"Douglas Truth"); wrtPersons->Close(); fstPersons->Close(); return 0; }
- To be able to complete a file, change the SaveOrder() method in the
IceCream.cs file as follows:
// IceCream3.cpp : main project file. #include "stdafx.h" using namespace System; using namespace System::IO; // This class is used to create and manage an ice scream // and to process an order public ref class CIceCream sealed { public: . . . No Change void SaveOrder() { String ^ strNameOfFile; Console::Write(L"Please enter your initials or the name " L"we will use to remember your order: "); strNameOfFile = Console::ReadLine(); strNameOfFile = strNameOfFile + L".icr"; // Find out if the user entered a name of a file // that is already in the machine if( File::Exists(strNameOfFile) ) { char answer; FileStream ^ stmIceCream = gcnew FileStream(strNameOfFile, FileMode::Create); BinaryWriter ^ bnwIceCream = gcnew BinaryWriter(stmIceCream); // If so, find out if the user wants to // replace the old file Console::WriteLine(L"The file you entered exists already."); Console::Write(L"Do you want to replace it(y/n)?"); answer = char::Parse(Console::ReadLine()); // If the customer wants to replace it... if( (answer == L'y') || (answer == 'Y') ) { // ... do so Console::WriteLine(L"The former order with the same " L"name will be replaced"); Console::WriteLine(L"\n=-= Ice Scream Vending Machine =-="); Console::WriteLine(L" Saving Order: {0}", strNameOfFile); bnwIceCream->Write(Flavor[ChoiceFlavor - 1]); bnwIceCream->Write(Container[ChoiceContainer - 1]); bnwIceCream->Write(Ingredient[ChoiceIngredient - 1]); bnwIceCream->Write(Scoops); bnwIceCream->Write(TotalPrice); } // If the customer wants to save the new order with // a different name else if( (answer == L'n') || (answer == 'N') ) { // Ask the user to enter a name to remember the order Console::Write(L"Please enter a name we will use " L"to remember this order: "); strNameOfFile = Console::ReadLine(); strNameOfFile = strNameOfFile + L".icr"; stmIceCream = gcnew FileStream(strNameOfFile, FileMode::Create); bnwIceCream = gcnew BinaryWriter(stmIceCream); Console::WriteLine(L"\n=-= Ice Scream Vending Machine =-="); Console::WriteLine(L" Saving Order: {0}", strNameOfFile); bnwIceCream->Write(Flavor[ChoiceFlavor - 1]); bnwIceCream->Write(Container[ChoiceContainer - 1]); bnwIceCream->Write(Ingredient[ChoiceIngredient - 1]); bnwIceCream->Write(Scoops); bnwIceCream->Write(TotalPrice); } else Console::WriteLine(L"Invalid Answer - We will close"); bnwIceCream->Close(); stmIceCream->Close(); } else { FileStream ^ stmIceCream = gcnew FileStream(strNameOfFile, FileMode::Create); BinaryWriter ^ bnwIceCream = gcnew BinaryWriter(stmIceCream); Console::WriteLine(L"\n=-= Ice Scream Vending Machine =-="); Console::WriteLine(L" Saving Order: {0}", strNameOfFile); bnwIceCream->Write(Flavor[ChoiceFlavor - 1]); bnwIceCream->Write(Container[ChoiceContainer - 1]); bnwIceCream->Write(Ingredient[ChoiceIngredient - 1]); bnwIceCream->Write(Scoops); bnwIceCream->Write(TotalPrice); bnwIceCream->Close(); stmIceCream->Close(); } } void OpenOrder() { . . . No Change } }; int main(array<System::String ^> ^args) { . . . No Change Console::WriteLine(); return 0; }
- Execute the application and test it. Here is an example:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Scream Vending Machine ----------------------------------- What type of flavor do you want? 1 - Vanilla 2 - Cream of Cocoa 3 - Chocolate Chip 4 - Organic Strawberry 5 - Butter Pecan 6 - Cherry Coke 7 - Chocolate Brownies 8 - Caramel Au Lait 9 - Chunky Butter 10 - Chocolate Cookie Your Choice? 8 ----------------------------------- What type of container do you want? 1 - Cone 2 - Cup 3 - Bowl Your Choice? 2 ----------------------------------- Do you want an ingredient or not 1 - No Ingredient 2 - Peanuts 3 - M & M 4 - Cookies Your Choice? 3 ----------------------------------- How many scoops(1, 2, or 3)? 2 ----------------------------------- =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Scream Order ----------------------------------- Flavor: Caramel Au Lait Container: Cup Ingredient: M & M Scoops: 2 Total Price: $3.10 =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Do you want us to remember this order the next time you come to get your ice scr eam (y/n)? Y Please enter your initials or the name we will use to remember your order: LS =-= Ice Scream Vending Machine =-= Saving Order: LS.icr Press any key to continue . . .
- Close the DOS window
Stream Reading
|
As opposed to writing to a stream, you may want to read
existing data from it. Before doing this, you can first specify your intent to
the streaming class using the FileMode enumerator. This can be done using
the FileStream class as follows:
using namespace System;
using namespace System::IO;
int main()
{
String ^ NameOfFile = L"Persons.spr";
/*
FileStream ^ fstPersons = gcnew FileStream(NameOfFile,
FileMode::Create);
BinaryWriter ^ wrtPersons = gcnew BinaryWriter(fstPersons);
wrtPersons->Write(L"James Bloch");
wrtPersons->Write(L"Catherina Wallace");
wrtPersons->Write(L"Bruce Lamont");
wrtPersons->Write(L"Douglas Truth");
wrtPersons->Close();
fstPersons->Close();
*/
FileStream ^ fstPersons = gcnew FileStream(NameOfFile, FileMode::Open);
return 0;
}
Once the stream is ready, you can get prepared to read data
from it. To support this, you can use the BinaryReader class. This class
provides two constructors. One of the constructors (the first) has the following
syntax:
public: BinaryReader(Stream ^ input);
This constructor takes as argument a Stream value,
which could be a FileStream object. After declaring a FileStream
variable using this constructor, you can read data from it. To do this, you can
call an appropriate method. This class provides an appropriate method for each
primitive data type.
After using the stream, you should close it to reclaim the
resources it was using. This is done by calling the Close() method.
Here is an example of using the mentioned methods:
using namespace System;
using namespace System::IO;
int main()
{
String ^ NameOfFile = L"Persons.spr";
/*
FileStream ^ fstPersons = gcnew FileStream(NameOfFile,
FileMode::Create);
BinaryWriter ^ wrtPersons = gcnew BinaryWriter(fstPersons);
wrtPersons->Write(L"James Bloch");
wrtPersons->Write(L"Catherina Wallace");
wrtPersons->Write(L"Bruce Lamont");
wrtPersons->Write(L"Douglas Truth");
wrtPersons->Close();
fstPersons->Close();
*/
FileStream ^ fstPersons = gcnew FileStream(NameOfFile,
FileMode::Open);
BinaryReader ^ rdrPersons = gcnew BinaryReader(fstPersons);
String ^ strLine = nullptr;
strLine = rdrPersons->ReadString();
Console::WriteLine(strLine);
strLine = rdrPersons->ReadString();
Console::WriteLine(strLine);
strLine = rdrPersons->ReadString();
Console::WriteLine(strLine);
strLine = rdrPersons->ReadString();
Console::WriteLine(strLine);
rdrPersons->Close();
fstPersons->Close();
Console::WriteLine();
return 0;
}
This would produce:
James Bloch Catherina Wallace Bruce Lamont Douglas Truth Press any key to continue . . .
- To be able to retrieve data from an existing file, change the IceCream.cs
file as follows:
// IceCream3.cpp : main project file. #include "stdafx.h" using namespace System; using namespace System::IO; // This class is used to create and manage an ice scream // and to process an order public ref class CIceCream sealed { public: // This is the base price of an ice scream // Optional values may be added to it static const double BasePrice = 1.55; // These arrays are used to build the components // of various ice screams private: array<String ^> ^ Flavor; array<String ^> ^ Container; array<String ^> ^ Ingredient; // Additional factor used to process an ice scream order int Scoops; double TotalPrice; // Variables that will hold the user's choice // These are declared "globally" so they can be // shared among methods int ChoiceFlavor; int ChoiceContainer; int ChoiceIngredient; // This default constructor is the best place for // us to initialize the array public: CIceCream() { Flavor = gcnew array<String ^>(10); Flavor[0] = L"Vanilla"; Flavor[1] = L"Cream of Cocoa"; Flavor[2] = L"Chocolate Chip"; Flavor[3] = L"Organic Strawberry"; Flavor[4] = L"Butter Pecan"; Flavor[5] = L"Cherry Coke"; Flavor[6] = L"Chocolate Brownies"; Flavor[7] = L"Caramel Au Lait"; Flavor[8] = L"Chunky Butter"; Flavor[9] = L"Chocolate Cookie"; Ingredient = gcnew array<String^>(4); Ingredient[0] = L"No Ingredient"; Ingredient[1] = L"Peanuts"; Ingredient[2] = L"M & M"; Ingredient[3] = L"Cookies"; Container = gcnew array<String^>(3); Container[0] = L"Cone"; Container[1] = L"Cup"; Container[2] = L"Bowl"; } // This method requests a flavor from the user and // returns the choice void ChooseFlavor() { // Make sure the user selects a valid number //that represents a flavor... do { // In case the user types a symbol that // is not a number try { Console::WriteLine(L"What type of flavor do you want?"); for (int i = 0; i < Flavor->Length; i++) Console::WriteLine(L"{0} - {1}", i + 1, Flavor[i]); Console::Write(L"Your Choice? "); ChoiceFlavor = int::Parse(Console::ReadLine()); } catch(FormatException ^) // display an appropriate message { Console::WriteLine(L"You must enter a valid number " L"and no other character!"); } // If the user typed an invalid number out of the // allowed range // let him or her know and provide another chance if( ChoiceFlavor < 1 || ChoiceFlavor > Flavor->Length) Console::WriteLine(L"Invalid Choice - Try Again!\n"); } while (ChoiceFlavor < 1 || ChoiceFlavor > Flavor->Length); } // This method allows the user to select a container void ChooseContainer() { // Make sure the user selects a valid number that // represents a container do { // If the user types a symbol that is not a number try { Console::WriteLine(L"What type of container do you want?"); for (int i = 0; i < Container->Length; i++) Console::WriteLine(L"{0} - {1}", i + 1, Container[i]); Console::Write(L"Your Choice? "); ChoiceContainer = int::Parse(Console::ReadLine()); } catch (FormatException ^) // display an appropriate message { Console::WriteLine(L"You must enter a valid " L"number and no other character!"); } // If the user typed an invalid number out of the // allowed range // let him or her know and provide another chance if( (ChoiceContainer < 1) || (ChoiceContainer > Container->Length) ) Console::WriteLine(L"Invalid Choice - Try Again!"); } while ((ChoiceContainer < 1) || (ChoiceContainer > Container->Length)); } void ChooseIngredient() { do { try { Console::WriteLine(L"Do you want an ingredient or not"); for (int i = 0; i < Ingredient->Length; i++) Console::WriteLine(L"{0} - {1}", i + 1, Ingredient[i]); Console::Write(L"Your Choice? "); ChoiceIngredient = int::Parse(Console::ReadLine()); } catch (FormatException ^) { Console::WriteLine(L"You must enter a valid " L"number and no other character!"); } if( (ChoiceIngredient < 1) || (ChoiceIngredient > Ingredient->Length) ) Console::WriteLine(L"Invalid Choice - Try Again!"); } while ((ChoiceIngredient < 1) || (ChoiceIngredient > Ingredient->Length)); } void SpecifyNumberOfScoops() { do { try { Console::Write(L"How many scoops(1, 2, or 3)? "); Scoops = int::Parse(Console::ReadLine()); } catch (FormatException ^) { Console::WriteLine(L"You must enter a valid number " L"and no other character!"); } if( Scoops < 1 || Scoops > 3 ) Console::WriteLine(L"Invalid Choice - Try Again!"); } while (Scoops < 1 || Scoops > 3); } // This method is used to process a customer order // It uses the values of the above methods void ProcessAnOrder() { double PriceIngredient, PriceScoop; // Let the user know that this is a vending machine Console::WriteLine(L"=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*="); Console::WriteLine(L"Ice Scream Vending Machine"); Console::WriteLine(L"-----------------------------------"); // Let the user select the components of the ice scream ChooseFlavor(); Console::WriteLine(L"-----------------------------------"); ChooseContainer(); Console::WriteLine(L"-----------------------------------"); ChooseIngredient(); Console::WriteLine(L"-----------------------------------"); SpecifyNumberOfScoops(); Console::WriteLine(L"-----------------------------------"); // If the user selects an ingredient instead of "No Ingredient", // add $0.50 to the order if( (ChoiceIngredient == 2) || (ChoiceIngredient == 3) || (ChoiceIngredient == 4) ) PriceIngredient = 0.50; else PriceIngredient = 0.00; // Instead of multiplying a number scoops to a value, // We will use an incremental value depending on // the number of scoops if( Scoops == 1 ) PriceScoop = 0.65; else if( Scoops == 2 ) PriceScoop = 1.05; else PriceScoop = 1.55; // Calculate the total price of the ice scream TotalPrice = BasePrice + PriceScoop + PriceIngredient; // Create the ice scream... // And display a receipt to the user DisplayReceipt(); } // This method is used to display a receipt to the user void DisplayReceipt() { Console::WriteLine(L"\n=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*="); Console::WriteLine(L"Ice Scream Order"); Console::WriteLine(L"-----------------------------------"); Console::WriteLine(L"Flavor: {0}", Flavor[ChoiceFlavor - 1]); Console::WriteLine(L"Container: {0}", Container[ChoiceContainer - 1]); Console::WriteLine(L"Ingredient: {0}", Ingredient[ChoiceIngredient - 1]); Console::WriteLine(L"Scoops: {0}", Scoops); Console::WriteLine(L"Total Price: {0:C}", TotalPrice); Console::WriteLine(L"=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\n"); } void SaveOrder() { String ^ strNameOfFile; Console::Write(L"Please enter your initials or the name " L"we will use to remember your order: "); strNameOfFile = Console::ReadLine(); strNameOfFile = strNameOfFile + L".icr"; // Find out if the user entered a name of a file // that is already in the machine if( File::Exists(strNameOfFile) ) { char answer; FileStream ^ stmIceCream = gcnew FileStream(strNameOfFile, FileMode::Create); BinaryWriter ^ bnwIceCream = gcnew BinaryWriter(stmIceCream); // If so, find out if the user wants to // replace the old file Console::WriteLine(L"The file you entered exists already."); Console::Write(L"Do you want to replace it(y/n)?"); answer = char::Parse(Console::ReadLine()); // If the customer wants to replace it... if( (answer == L'y') || (answer == 'Y') ) { // ... do so Console::WriteLine(L"The former order with the same " L"name will be replaced"); Console::WriteLine(L"\n=-= Ice Scream Vending Machine =-="); Console::WriteLine(L" Saving Order: {0}", strNameOfFile); bnwIceCream->Write(Flavor[ChoiceFlavor - 1]); bnwIceCream->Write(Container[ChoiceContainer - 1]); bnwIceCream->Write(Ingredient[ChoiceIngredient - 1]); bnwIceCream->Write(Scoops); bnwIceCream->Write(TotalPrice); } // If the customer wants to save the new order with // a different name else if( (answer == L'n') || (answer == 'N') ) { // Ask the user to enter a name to remember the order Console::Write(L"Please enter a name we will use " L"to remember this order: "); strNameOfFile = Console::ReadLine(); strNameOfFile = strNameOfFile + L".icr"; stmIceCream = gcnew FileStream(strNameOfFile, FileMode::Create); bnwIceCream = gcnew BinaryWriter(stmIceCream); Console::WriteLine(L"\n=-= Ice Scream Vending Machine =-="); Console::WriteLine(L" Saving Order: {0}", strNameOfFile); bnwIceCream->Write(Flavor[ChoiceFlavor - 1]); bnwIceCream->Write(Container[ChoiceContainer - 1]); bnwIceCream->Write(Ingredient[ChoiceIngredient - 1]); bnwIceCream->Write(Scoops); bnwIceCream->Write(TotalPrice); } else Console::WriteLine(L"Invalid Answer - We will close"); bnwIceCream->Close(); stmIceCream->Close(); } else { FileStream ^ stmIceCream = gcnew FileStream(strNameOfFile, FileMode::Create); BinaryWriter ^ bnwIceCream = gcnew BinaryWriter(stmIceCream); Console::WriteLine(L"\n=-= Ice Scream Vending Machine =-="); Console::WriteLine(L" Saving Order: {0}", strNameOfFile); bnwIceCream->Write(Flavor[ChoiceFlavor - 1]); bnwIceCream->Write(Container[ChoiceContainer - 1]); bnwIceCream->Write(Ingredient[ChoiceIngredient - 1]); bnwIceCream->Write(Scoops); bnwIceCream->Write(TotalPrice); bnwIceCream->Close(); stmIceCream->Close(); } } void OpenOrder() { String ^ strNameOfFile; String ^ SelectedFlavor; String ^ SelectedContainer; String ^ SelectedIngredient; // Ask the user to enter a name of a previously saved order Console::Write(L"Please enter the name you previously " L"gave to remember your order: "); strNameOfFile = Console::ReadLine(); strNameOfFile = strNameOfFile + L".icr"; FileStream ^ stmIceCream = gcnew FileStream(strNameOfFile, FileMode::Open); BinaryReader ^ bnrIceCream = gcnew BinaryReader(stmIceCream); // Find out if this order was previously saved in the machine if( File::Exists(strNameOfFile) ) { // If so, open it SelectedFlavor = bnrIceCream->ReadString(); SelectedContainer = bnrIceCream->ReadString(); SelectedIngredient = bnrIceCream->ReadString(); Scoops = bnrIceCream->ReadInt32(); TotalPrice = bnrIceCream->ReadDouble(); // And display it to the user Console::WriteLine(L"\n=-= Ice Scream Vending Machine =-="); Console::WriteLine(L" Previous Order: {0}", strNameOfFile); Console::WriteLine(L"Flavor: {0}", SelectedFlavor); Console::WriteLine(L"Container: {0}", SelectedContainer); Console::WriteLine(L"Ingredient: {0}", SelectedIngredient); Console::WriteLine(L"Scoops: {0}", Scoops); Console::WriteLine(L"Total Price: {0:C}\n", TotalPrice); bnrIceCream->Close(); stmIceCream->Close(); } else Console::WriteLine(L"The name you entered is not " L"registered in our previous orders"); } }; int main(array<System::String ^> ^args) { String ^ answer = L"n"; CIceCream ^ ic = gcnew CIceCream(); Console::Write(L"Do you want to re-order a previously " L"saved order(y/n)? "); answer = Console::ReadLine(); if( (answer == L"y") || (answer == L"Y") ) ic->OpenOrder(); else { ic->ProcessAnOrder(); Console::Write(L"Do you want us to remember this " L"order the next time you come to " L"get your ice scream (y/n)? "); answer = Console::ReadLine(); if( (answer == L"y") || (answer == L"Y") ) ic->SaveOrder(); else Console::WriteLine(L"\nIt was nice serving you." L"\nCome Again!!!\n"); } Console::WriteLine(); return 0; }
- Execute the application and test it. Here is an example:
Do you want to re-order a previously saved order(y/n)? Y Please enter the name you previously gave to remember your order: LS =-= Ice Scream Vending Machine =-= Previous Order: LS.icr Flavor: Caramel Au Lait Container: Cup Ingredient: M & M Scoops: 2 Total Price: $3.10 Press any key to continue . . .
- Close the DOS window
- Execute the application again and test it. Here is an example:
Do you want to re-order a previously saved order(y/n)? w =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Scream Vending Machine ----------------------------------- What type of flavor do you want? 1 - Vanilla 2 - Cream of Cocoa 3 - Chocolate Chip 4 - Organic Strawberry 5 - Butter Pecan 6 - Cherry Coke 7 - Chocolate Brownies 8 - Caramel Au Lait 9 - Chunky Butter 10 - Chocolate Cookie Your Choice? 5 ----------------------------------- What type of container do you want? 1 - Cone 2 - Cup 3 - Bowl Your Choice? 2 ----------------------------------- Do you want an ingredient or not 1 - No Ingredient 2 - Peanuts 3 - M & M 4 - Cookies Your Choice? 1 ----------------------------------- How many scoops(1, 2, or 3)? 1 ----------------------------------- =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Scream Order ----------------------------------- Flavor: Butter Pecan Container: Cup Ingredient: No Ingredient Scoops: 1 Total Price: $2.20 =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Do you want us to remember this order the next time you come to get your ice scream (y/n)? y Please enter your initials or the name we will use to remember your order: DIC =-= Ice Scream Vending Machine =-= Saving Order: DIC.icr Press any key to continue . . .
- Close the DOS window
- Execute the application again and test it. Here is an example:
Do you want to re-order a previously saved order(y/n)? n =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Scream Vending Machine ----------------------------------- What type of flavor do you want? 1 - Vanilla 2 - Cream of Cocoa 3 - Chocolate Chip 4 - Organic Strawberry 5 - Butter Pecan 6 - Cherry Coke 7 - Chocolate Brownies 8 - Caramel Au Lait 9 - Chunky Butter 10 - Chocolate Cookie Your Choice? 9 ----------------------------------- What type of container do you want? 1 - Cone 2 - Cup 3 - Bowl Your Choice? 3 ----------------------------------- Do you want an ingredient or not 1 - No Ingredient 2 - Peanuts 3 - M & M 4 - Cookies Your Choice? 4 ----------------------------------- How many scoops(1, 2, or 3)? 3 ----------------------------------- =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Scream Order ----------------------------------- Flavor: Chunky Butter Container: Bowl Ingredient: Cookies Scoops: 3 Total Price: $3.60 =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Do you want us to remember this order the next time you come to get your ice scream (y/n)? Y Please enter your initials or the name we will use to remember your order: LS The file you entered exists already. Do you want to replace it(y/n)?Y The former order with the same name will be replaced =-= Ice Scream Vending Machine =-= Saving Order: LS.icr Press any key to continue . . .
- Close the DOS window
No comments:
Post a Comment