The FileStream object represents a stream that points to a file on a disk or network path. This class provides a way to read and write bytes in a file, but often performs these functions using StreamReader or StreamWriter. This is because the FileStream class operates on byte and byte arrays, while the Stream class operates on character data. Character data is easy to use, but some operations, such as random file access (accessing data at a point in the middle of a file), must be performed by the FileStream object, which is described later.
There are several other ways to create a FileStream object. Constructors have many different overloaded versions, and the simplest constructors have only two parameters, namely file names and FileMode enumeration values.
Copy Code code as follows:
FileStream afile = new FileStream (filename, filemode.member);
The FileMode enumeration has several members that specify how to open or create a file. These enumeration members are described later. Another common constructor is the following:
Copy Code code as follows:
FileStream afile = new FileStream (filename, Filemode.member, FileAccess. Member);
The third parameter is a member of the FileAccess enumeration, which specifies the function of the stream. The members of the FileAccess enumeration are shown in table 22-6.
Table 22-6
Members |
Description |
Read |
Open a file for read-only |
Write |
Open a file for writing only |
ReadWrite |
Open file for reading and writing |
An operation specified on a file that is not a FileAccess enumeration member can cause an exception to be thrown. The purpose of this property is to change the user's access rights to the file based on the user's authentication level.
In a version where the FileStream constructor does not use the FileAccess enumeration parameter, the default value FileAccess is used. ReadWrite.
The FileMode enumeration member is shown in table 22-7. What happens with each value depends on whether the specified filename represents an existing file. Note that the entry in this table represents the location of the stream when the stream was created, and the topic is discussed in detail in the next section. Unless specifically stated, the stream points to the beginning of the file.
Table 22-7
Members |
File exists |
file does not exist |
Append |
Opens the file, and the stream points to the end of the file and can only be used in conjunction with the enumeration FileAccess.Write |
Create a new file. Can only be used in conjunction with enumerated FileAccess.Write |
Create |
Delete the file, and then create a new file |
Create a new file |
CreateNew |
Throw an exception |
Create a new file |
Open |
Opens an existing file, and the stream points to the beginning of the file |
Throw an exception |
OpenOrCreate |
Opens the file, and the stream points to the beginning of the file |
Create a new file |
Truncate |
Open an existing file and clear its contents. The stream points to the beginning of the file, preserving the initial creation date of the file |
Throw an exception |
Both the file and FileInfo classes provide the OpenRead () and Openwrite () methods, making it easier to create FileStream objects. The former opens a read-only access file, which only allows the file to be written. These provide shortcuts, so you do not have to provide all the preceding information in the form of arguments to the FileStream constructor. For example, the following line of code opens the Data.txt file for read-only access:
Copy Code code as follows:
FileStream afile = File.openread ("Data.txt");
Note that the following code performs the same function:
Copy Code code as follows:
FileInfo afileinfo = new FileInfo ("Data.txt");
FileStream afile = Afile.openread ();
1. File location
The FileStream class maintains an internal file pointer that points to the location of the next read and write operation in the file. In most cases, when you open a file, it points to the beginning of the file, but this pointer can be modified. This allows the application to read and write anywhere in the file, randomly access the file, or jump directly to a specific location in the file. This is very time-saving when working with large files, because you can immediately navigate to the correct location.
The method for implementing this functionality is the Seek () method, which has two parameters: the first parameter sets the distance that the file pointer moves in bytes. The second parameter sets the starting position of the start calculation, represented by a value of the SeekOrigin enumeration. The Seek Origin enumeration contains 3 values: Begin, Current, and end.
For example, the following line of code moves the file pointer to the 8th byte of the file, starting at the 1th byte of the file:
Copy Code code as follows:
Afile.seek (8,seekorigin.begin);
The following line of code moves the pointer forward 2 bytes, starting at the current position. If you execute the following code after the line above, the file pointer points to the 10th byte of the file:
Copy Code code as follows:
Afile.seek (2,seekorigin.current);
Note that file pointers also change when you read and write files. After reading 10 bytes, the file pointer points to the byte after the 10th byte being read.
You can also specify a negative lookup location, which can be used in conjunction with the Seekorigin.end enumeration value to find a location close to the end of the file. The following code looks for the penultimate byte in the file:
Copy Code code as follows:
Afile.seek (–5, seekorigin.end);
Files accessed in this manner are sometimes referred to as random access files because the application can access any location in the file. The stream class, which is described later, can continuously access the file and does not allow the file pointer to be manipulated in this manner.
2. Reading data
Reading data using the FileStream class is not as easy as reading data using the StreamReader class described later in this chapter. This is because the FileStream class can only handle raw bytes (raw byte). The ability to handle raw bytes enables the FileStream class to be used with any data file, not just a text file. By reading Byte data, the FileStream object can be used to read files for images and sounds. The price of this flexibility is that you cannot use the FileStream class to read data directly into a string, but you can do this with the StreamReader class. But there are several conversion classes that can easily convert a byte array to a character array, or do the opposite.
The FileStream.Read () method is the primary means of accessing data from a file that the FileStream object points to. This method reads the data from the file and writes the data to a byte array. It has three parameters: the first parameter is a byte array that is transferred in to accept the data in the FileStream object. The second parameter is where the data begins to be written in a byte array. It is usually 0, which means that the data is written to the file from the beginning of the array. The last parameter specifies how many bytes to read from the file.
The following example shows the reading of data from a random access file. The file to be read is actually the class file created for this example.
Try it: Read data from random access files
(1) Create a new console application ReadFile under the directory C:\BegVCSharp\Chapter22.
(2) Add the following using directive at the top of the Program.cs file:
Copy Code code as follows:
Using System;
Using System.Collections.Generic;
Using System.Text;
Using System.IO;
(3) Add the following code to the main () method:
Copy Code code as follows:
static void Main (string[] args)
{
byte[] Bydata = new byte[200];
char[] Chardata = new char[200];
Try
{
FileStream afile = new FileStream ("E:\\workplace\\testsolution\\test.consoleapplication\\program.cs", FileMode.Open );
Afile.seek (135,seekorigin.begin);
Afile.read (bydata,0,200);
}
catch (IOException E)
{
Console.WriteLine ("An IO exception has been thrown!");
Console.WriteLine (E.tostring ());
Console.readkey ();
Return
}
Decoder d = Encoding.UTF8.GetDecoder ();
D.getchars (bydata, 0, Bydata.length, chardata, 0);
Console.WriteLine (Chardata);
Console.readkey ();
}
(4) Run the application. The result is shown in Figure 22-2.
Figure 22-2
Description of the example
This application opens its own. cs file for reading. It is used in the following line of code. The string navigates up to two directories and finds the file:
Copy Code code as follows:
FileStream afile = new FileStream ("E:\\workplace\\testsolution\\test.consoleapplication\\program.cs", FileMode.Open );
The following two lines of code implement the lookup and read bytes from the exact location of the file:
Copy Code code as follows:
Afile.seek (135,seekorigin.begin);
Afile.read (bydata,0,200);
The first line of code moves the file pointer to the 135th byte of the file. In Program.cs, this is the namespace "n"; The preceding 135 characters are the using directive and the associated #region. The second row of the next 200 bytes is read into the Bydata byte array.
Note that these two lines of code are encapsulated in a try...catch block to handle the exceptions that might be thrown.
Copy Code code as follows:
Try
{
Afile.seek (135,seekorigin.begin);
Afile.read (bydata,0,100);
}
catch (IOException E)
{
Console.WriteLine ("An IO exception has been thrown!");
Console.WriteLine (E.tostring ());
Console.readkey ();
Return
}
All operations involved in file IO can throw exceptions of type IOException. All product code must contain error handling, especially when dealing with file systems. All the examples in this chapter have the basic form of error handling.
When you get a byte array from a file, you need to convert it to a character array to display it in the console. To do this, use the decoder class of the System.Text namespace. This class is used to convert raw bytes to more useful items, such as characters:
Copy Code code as follows:
Decoder d = Encoding.UTF8.GetDecoder ();
D.getchars (bydata, 0, Bydata.length, chardata, 0);
The code creates the decoder object based on the UTF8 encoding pattern. This is the Unicode encoding mode. Then call the GetChars () method, which extracts the byte array and converts it to a character array. When you are done, you can output a character array to the console.
3. Write Data
The process of writing data to random access files is very similar to reading data from. First you need to create a byte array; The easiest way is to build the array of characters to write to the file first. It is then converted to a byte array using the Encoder object, which is very similar to the decoder. Finally, the write () method is invoked to transfer the byte array to the file.
The following builds a simple example to illustrate its process.
Try it: Write data to random access files
(1) Create a new console application WriteFile in the C:\BegVCSharp\Chapter22 directory.
(2) as shown above, add the following using directive at the top of the Program.cs file:
Copy Code code as follows:
Using System;
Using System.Collections.Generic;
Using System.Text;
Using System.IO;
(3) Add the following code to the main () method:
Copy Code code as follows:
static void Main (string[] args)
{
Byte[] Bydata;
Char[] Chardata;
Try
{
FileStream afile = new FileStream ("Temp.txt", FileMode.Create);
Chardata = "My pink half of the drainpipe.". ToCharArray ();
Bydata = new Byte[chardata.length];
Encoder e = Encoding.UTF8.GetEncoder ();
E.getbytes (chardata, 0, Chardata.length, bydata, 0, true);
Move file pointer to beginning of file.
Afile.seek (0, Seekorigin.begin);
Afile.write (bydata, 0, bydata.length);
}
catch (IOException ex)
{
Console.WriteLine ("An IO exception has been thrown!");
Console.WriteLine (ex. ToString ());
Console.readkey ();
Return
}
}
(4) Run the application. Turn it off later.
(5) Navigate to the application directory--the file has been saved in the directory because we are using a relative path. The directory is located in the Writefile\bin\debug folder. Open the Temp.txt file. You can see the text in the file as shown in Figure 22-3.
Figure 22-3
Description of the example
This application opens the file in its own directory and writes a simple string in the file. Structurally This example is very similar to the previous example, but instead of the read () with write (), encoder replaces the decoder.
The following line of code creates a character array using the ToCharArray () static method of the String class. Because all things in C # are objects, the text "My pink half of the drainpipe." is actually a string object, so you can even raise these static methods in a string.
Copy Code code as follows:
Chardata = "My pink half of the drainpipe.". ToCharArray ();
The following line of code shows how to convert a character array to the correct byte array required by the FileStream object.
Copy Code code as follows:
Encoder e = Endoding.UTF8.GetEncoder ();
E.getbytes (Chardata,0,chardata.length, bydata,0,true);
This time, you want to create the encoder object based on the UTF8 encoding method. Unicode can also be used for decoding. Here before writing the stream, you need to encode the character data into the correct byte format. You can do this in the GetBytes () method, which converts a character array to an array of bytes and takes the character array as the first argument (the Chardata in this case) and takes the subscript of the starting position in the array as the second argument (0 for the beginning of the array). The third parameter is the number of characters to convert (the number of elements in the Chardata.length,chardata array). The fourth parameter is the byte array in which the data is placed (Bydata), and the fifth parameter is the subscript (0 for the beginning of the Bydata array) that begins the write position in the byte array.
The last parameter determines whether the encoder object should update its state after the end, that is, whether the encoder object still retains its original memory location in the byte array. This helps to call the encoder object later, but it makes little sense when only a single call is made. The last call to encoder must set this argument to true to empty its memory and dispose of the object for garbage collection.
After that, writing a byte array to FileStream using the Write () method is simple:
Copy Code code as follows:
Afile.seek (0,seekorigin.begin);
Afile.write (bydata,0,bydata.length);
As with the Read () method, the Write () method also has three parameters: the array to write, the subscript to begin writing, and the number of bytes to write.