|
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.
|
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.
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.
Practical
Learning: Introducing Streaming |
|
- Start Microsoft Visual C# and create a Console
Application named IceCream3
- To save the project, on the Standard toolbar, click the Save All button
- Change the Solution Name to VendingMachine3
- Accept the Name of the project as IceCream3 and click Save
- To create a new class, on the main menu, click Project -> Add Class...
- Set the Name to IceCream and click Add
- Change the file as follows:
using System;
namespace IceCream3
{
delegate void Request();
// This class is used to create and manage an Ice Cream
// and to process an order
public sealed class IceCream
{
// This is the base price of an Ice Cream
// Optional values may be added to it
public const decimal BasePrice = 1.55M;
// These arrays are used to build the components
// of various Ice Creams
// In C#, we can allocate an array's memory in
// the body of the class
private string[] Flavor;
private string[] Container;
private string[] Ingredient;
// Additional factor used to process an Ice Cream order
private int Scoops;
private decimal 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 IceCream()
{
Flavor = new string[10];
Flavor[0] = "Vanilla";
Flavor[1] = "Cream of Cocoa";
Flavor[2] = "Chocolate Chip";
Flavor[3] = "Organic Strawberry";
Flavor[4] = "Butter Pecan";
Flavor[5] = "Cherry Coke";
Flavor[6] = "Chocolate Brownies";
Flavor[7] = "Caramel Au Lait";
Flavor[8] = "Chunky Butter";
Flavor[9] = "Chocolate Cookie";
Ingredient = new string[4];
Ingredient[0] = "No Ingredient";
Ingredient[1] = "Peanuts";
Ingredient[2] = "M & M";
Ingredient[3] = "Cookies";
Container = new string[3];
Container[0] = "Cone";
Container[1] = "Cup";
Container[2] = "Bowl";
}
// This method requests a flavor from the user and
// returns the choice
public 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("What type of flavor do you want?");
for (int i = 0; i < Flavor.Length; i++)
Console.WriteLine("{0} - {1}", i + 1, Flavor[i]);
Console.Write("Your Choice? ");
ChoiceFlavor = int.Parse(Console.ReadLine());
}
catch (FormatException) // display an appropriate message
{
Console.WriteLine("You must enter a valid 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 (ChoiceFlavor < 1 || ChoiceFlavor > Flavor.Length)
Console.WriteLine("Invalid Choice - Try Again!\n");
} while (ChoiceFlavor < 1 || ChoiceFlavor > Flavor.Length);
}
// This method allows the user to select a container
public 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("What type of container do you want?");
for (int i = 0; i < Container.Length; i++)
Console.WriteLine("{0} - {1}", i + 1, Container[i]);
Console.Write("Your Choice? ");
ChoiceContainer = int.Parse(Console.ReadLine());
}
catch (FormatException) // display an appropriate message
{
Console.WriteLine("You must enter a valid " +
"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("Invalid Choice - Try Again!");
} while ((ChoiceContainer < 1) ||
(ChoiceContainer > Container.Length));
}
public void ChooseIngredient()
{
do
{
try
{
Console.WriteLine("Do you want an ingredient or not");
for (int i = 0; i < Ingredient.Length; i++)
Console.WriteLine("{0} - {1}",
i + 1,
Ingredient[i]);
Console.Write("Your Choice? ");
ChoiceIngredient = int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("You must enter a valid " +
"number and no other character!");
}
if ((ChoiceIngredient < 1) ||
(ChoiceIngredient > Ingredient.Length))
Console.WriteLine("Invalid Choice - Try Again!");
} while ((ChoiceIngredient < 1) ||
(ChoiceIngredient > Ingredient.Length));
}
public void SpecifyNumberOfScoops()
{
do
{
try
{
Console.Write("How many scoops(1, 2, or 3)? ");
Scoops = int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("You must enter a valid number " +
"and no other character!");
}
if (Scoops < 1 || Scoops > 3)
Console.WriteLine("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
public void ProcessAnOrder()
{
// int ChoiceFlavor;
// int ChoiceContainer;
// int ChoiceIngredient;
decimal PriceIngredient, PriceScoop;
// Let the user know that this is a vending machine
Console.WriteLine("=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=");
Console.WriteLine("Ice Cream Vending Machine");
Console.WriteLine("-----------------------------------");
// Let the user select the components of the Ice Cream
Request Get = new Request(ChooseFlavor);
Get();
Console.WriteLine("-----------------------------------");
Get = new Request(ChooseContainer);
Get();
Console.WriteLine("-----------------------------------");
Get = new Request(ChooseIngredient);
Get();
Console.WriteLine("-----------------------------------");
Get = new Request(SpecifyNumberOfScoops);
Get();
Console.WriteLine("-----------------------------------");
// 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.50M;
else
PriceIngredient = 0.00M;
// 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.65M;
else if (Scoops == 2)
PriceScoop = 1.05M;
else
PriceScoop = 1.55M;
// Calculate the total price of the Ice Cream
TotalPrice = BasePrice + PriceScoop + PriceIngredient;
// Create the Ice Cream...
// And display a receipt to the user
DisplayReceipt();
}
// This method is used to display a receipt to the user
public void DisplayReceipt()
{
Console.WriteLine("\n=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=");
Console.WriteLine("Ice Cream Order");
Console.WriteLine("-----------------------------------");
Console.WriteLine("Flavor: {0}",
Flavor[ChoiceFlavor - 1]);
Console.WriteLine("Container: {0}",
Container[ChoiceContainer - 1]);
Console.WriteLine("Ingredient: {0}",
Ingredient[ChoiceIngredient - 1]);
Console.WriteLine("Scoops: {0}", Scoops);
Console.WriteLine("Total Price: {0:C}", TotalPrice);
Console.WriteLine("=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\n");
}
}
}
- Access the Program.cs file and change it as follows:
using System;
namespace IceCream3
{
class Program
{
static int Main(string[] args)
{
IceCream ic = new IceCream();
Request process = new Request(ic.ProcessAnOrder);
process();
return 0;
}
}
}
- Execute the project and test it. Here is an example:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
Ice Cream 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 Cream Order
-----------------------------------
Flavor: Chocolate Chip
Container: Bowl
Ingredient: Cookies
Scoops: 3
Total Price: $3.60
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
Press any key to continue . . .
- Close the DOS window
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 System;
class Exercise
{
static int Main()
{
string NameOfFile = "Employees.spr";
return 0;
}
}
Practical
Learning: Specifying the Name of a File |
|
- Access the IceCream.cs file and add a new public method named SaveOrder
of type void as follows:
using System;
namespace IceCream3
{
// This class is used to create and manage an Ice Cream
// and to process an order
public sealed class IceCream
{
. . . No Change
// This method is used to display a receipt to the user
public void DisplayReceipt()
{
. . . No Change
}
public void SaveOrder()
{
string NameOfFile;
Console.Write("Please enter your initials or the " +
"name we will use to remember your order: ");
NameOfFile = Console.ReadLine();
}
}
}using System;
namespace IceCream3
{
delegate void Request();
// This class is used to create and manage an Ice Cream
// and to process an order
public sealed class IceCream
{
. . . No Change
// This method is used to display a receipt to the user
public void DisplayReceipt()
{
. . . No Change
}
public void SaveOrder()
{
string NameOfFile;
Console.Write("Please enter your initials or the " +
"name we will use to remember your order: ");
NameOfFile = Console.ReadLine();
}
}
}
|
- Access the Program.cs file and change it as follows:
using System;
namespace IceCream3
{
class Program
{
static int Main(string[] args)
{
char answer = 'n';
IceCream ic = new IceCream();
Request process = new Request(ic.ProcessAnOrder);
process();
Console.Write("Do you want us to remember this " +
"order the next time you come to " +
"get your Ice Cream (y/n)? ");
answer = char.Parse(Console.ReadLine());
if (answer == 'y' || answer == 'Y')
ic.SaveOrder();
return 0;
}
}
}
|
- Execute the project and test it
- Close the DOS window
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:
using System;
class Exercise
{
static int Main()
{
string NameOfFile = "C:\\Documents and " +
"Settings\\Business Records\\Employees.spr";
return 0;
}
}
Alternative, you can keep one backslash in each placeholder
but precede the value of the string with the @ symbol. Here is an example:
using System;
class Exercise
{
static int Main()
{
string NameOfFile = @"C:\Documents and " +
"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.
|
|