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) member functions to create, save, open, copy, move, delete, or check the existence of a file.
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 member function. 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 member function returns true. If the compiler cannot find the file, the member function 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.
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() member function 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() member function returns a Stream value, in this case a FileStream value. As the File.Create() member function 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() member function 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);
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:
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:
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:
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 member functions. 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: System::Void btnSave_Click(System::Object^ sender, System::EventArgs^ e) { String ^ NameOfFile = L"Persons.spr"; FileStream ^ fstPersons = gcnew FileStream(NameOfFile, FileMode::Create); }
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: System::Void btnSave_Click(System::Object^ sender, System::EventArgs^ e) { String ^ NameOfFile = L"Persons.spr"; FileStream ^ fstPersons = gcnew FileStream(NameOfFile, FileMode::Create); BinaryWriter ^ wrtPersons = gcnew BinaryWriter(fstPersons); } Most classes that are used to add values to a stream are equipped with a member function called Write. This is also the case for the BinaryWriter class. This member function takes as argument the value that must be written to the stream. The member function 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:
System::Void btnSave_Click(System::Object^ sender, System::EventArgs^ e) { String ^ NameOfFile = L"Persons.spr"; FileStream ^ fstPersons = gcnew FileStream(NameOfFile, FileMode::Create); BinaryWriter ^ wrtPersons = gcnew BinaryWriter(fstPersons); wrtPersons->Write(txtPerson1->Text); wrtPersons->Write(txtPerson2->Text); wrtPersons->Write(txtPerson3->Text); wrtPersons->Write(txtPerson4->Text); txtPerson1->Text = L""; txtPerson2->Text = L""; txtPerson3->Text = L""; txtPerson4->Text = L""; }
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() member function of the class(es) you were using. Here are examples: System::Void btnSave_Click(System::Object^ sender, System::EventArgs^ e) { String ^ NameOfFile = L"Persons.spr"; FileStream ^ fstPersons = gcnew FileStream(NameOfFile, FileMode::Create); BinaryWriter ^ wrtPersons = gcnew BinaryWriter(fstPersons); wrtPersons->Write(txtPerson1->Text); wrtPersons->Write(txtPerson2->Text); wrtPersons->Write(txtPerson3->Text); wrtPersons->Write(txtPerson4->Text); wrtPersons->Close(); fstPersons->Close(); txtPerson1->Text = L""; txtPerson2->Text = L""; txtPerson3->Text = L""; txtPerson4->Text = L""; }
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: System::Void btnOpen_Click(System::Object^ sender, System::EventArgs^ e) { String ^ NameOfFile = L"Persons.spr"; FileStream ^ fstPersons = gcnew FileStream(NameOfFile, FileMode::Open); } 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 member function. This class provides an appropriate member function 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() member function. Here is an example of using the mentioned member functions: System::Void btnOpen_Click(System::Object^ sender, System::EventArgs^ e) { String ^ NameOfFile = L"Persons.spr"; FileStream ^ fstPersons = gcnew FileStream(NameOfFile, FileMode::Open); BinaryReader ^ rdrPersons = gcnew BinaryReader(fstPersons); String ^ strLine = nullptr; strLine = rdrPersons->ReadString(); txtPerson1->Text = strLine; strLine = rdrPersons->ReadString(); txtPerson2->Text = strLine; strLine = rdrPersons->ReadString(); txtPerson3->Text = strLine; strLine = rdrPersons->ReadString(); txtPerson4->Text = strLine; rdrPersons->Close(); fstPersons->Close(); }
So far, to handle exceptions, we were using the try, catch, and throw keywords. These allowed us to perform normal assignments in a try section and then handle an exception, if any, in a catch block. We also mentioned that, when you create a stream, the operating system must allocate resources and dedicate them to the file processing operations. Additional resources may be provided for the object that is in charge of writing to, or reading from, the stream. We also saw that, when the streaming was over, we should free the resources and give them back to the operating system. To do this, we called the Close() member function of the variable that was using resources. More than any other assignment, file processing is in prime need of exception handling. During file processing, there are many things that can go wrong. For this reason, the creation and/or management of streams should be performed in a try block to get ready to handle exceptions that would occur. Besides actually handling exceptions, you can use the finally keyword to free resources. The finally keyword is used to create a section of an exception. Like catch, a finally block cannot exist by itself. It can be created following a try section. The formula used would be: try { } finally { } Based on this:
Because the finally clause always gets executed, you can include any type of code in it but it is usually appropriate to free the resources that were allocated such as those used during streaming. Here is an example: System::Void btnSave_Click(System::Object^ sender, System::EventArgs^ e) { String ^ NameOfFile = L"Persons.spr"; FileStream ^ fstPersons = gcnew FileStream(NameOfFile, FileMode::Create); BinaryWriter ^ wrtPersons = gcnew BinaryWriter(fstPersons); try { wrtPersons->Write(txtPerson1->Text); wrtPersons->Write(txtPerson2->Text); wrtPersons->Write(txtPerson3->Text); wrtPersons->Write(txtPerson4->Text); } finally { wrtPersons->Close(); fstPersons->Close(); } txtPerson1->Text = L""; txtPerson2->Text = L""; txtPerson3->Text = L""; txtPerson4->Text = L""; } In the same way, you can use a finally section to free resources used when reading from a stream. Of course, since the whole block of code starts with a try section, it is used for exception handling. This means that you can add the necessary and appropriate catch section(s) but you don't have to.
In the previous lesson of our introduction to file processing, we behaved as if everything was alright. Unfortunately, file processing can be very strict in its assignments. Fortunately, the .NET Framework provides various Exception-oriented classes to deal with almost any type of exception you can think of. One of the most important aspects of file processing is the name of the file that will be dealt with. In some cases you can provide this name to the application or document. In some other cases, you would let the user specify the name of the path. Regardless of how the name of the file would be provided to the operating system, when this name is acted upon, the compiler will be asked to work on the file. If the file doesn't exist, the operation cannot be carried. Furthermore, the compiler would throw an error. There are many other exceptions that can be thrown as a result of something going bad during file processing: FileNotFoundException: The exception thrown when a file has not been found is of type FileNotFoundException. Here is an example of handling it: using namespace System; using namespace System::IO; int main() { /* String ^ NameOfFile = L"Members.clb"; FileStream ^ fstPersons = gcnew FileStream(NameOfFile, FileMode::Create); BinaryWriter ^ wrtPersons = gcnew BinaryWriter(fstPersons); try { wrtPersons->Write(L"James Bloch"); wrtPersons->Write(L"Catherina Wallace"); wrtPersons->Write(L"Bruce Lamont"); wrtPersons->Write(L"Douglas Truth"); } finally { wrtPersons->Close(); fstPersons->Close(); }*/ String ^ NameOfFile = L"Members.clc"; String ^ strLine = L""; try { FileStream ^ fstMembers = gcnew FileStream(NameOfFile, FileMode::Open); BinaryReader ^ rdrMembers = gcnew BinaryReader(fstMembers); try { strLine = rdrMembers->ReadString(); Console::WriteLine(strLine); strLine = rdrMembers->ReadString(); Console::WriteLine(strLine); strLine = rdrMembers->ReadString(); Console::WriteLine(strLine); strLine = rdrMembers->ReadString(); Console::WriteLine(strLine); } finally { rdrMembers->Close(); fstMembers->Close(); } } catch (FileNotFoundException ^ ex) { Console::Write(L"Error: " + ex->Message); Console::WriteLine(L" May be the file doesn't exist " + L"or you typed it wrong!"); } return 0; } Here is an example of what this would produce: Error: Could not find file 'c:\Documents and Settings\Administrator \My Documents\Visual Studio 2005\Projects\FileProcessing2 \FileProcessing2\Members.clc'. May be the file doesn't exist or you typed it wrong! Press any key to continue . . . IOException: As mentioned already, during file processing, anything could go wrong. If you don't know what caused an error, you can throw the IOException exception. |
|
|||||||||||||||||||||||||||||||||||||
|