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 uses StreamReader or StreamWriter to perform these functions. This is because the FileStream class operates on byte and byte arrays, and the Stream class operates on character data. Character data is easy to use, but some operations, such as random file access (accessing data from a point in the middle of a file), must be performed by the FileStream object, which is described later.
There are several ways to create FileStream objects. Constructors have many different overloaded versions, and the simplest constructors only have two parameters, the file name and the FileMode enumeration value.
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 as follows:
FileStream afile = new FileStream (filename, Filemode.member, FileAccess. Member); |
The third parameter is a member of the FileAccess enumeration that specifies the role of the stream. The members of the FileAccess enumeration are shown in table 22-6.
Table 22-6
Become a member |
Speak clearly |
Read |
Open file for read-only |
Write |
Open file for write-only |
ReadWrite |
Open file for read-write |
The action specified on the file not FileAccess enumeration member causes an exception to be thrown. The purpose of this property is to change the user's access to the file based on the user's level of authentication.
In a version of the FileStream constructor that 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 file name represents the existing files. Note the items in this table represent where the stream points to in the file when the stream is created, and this topic is discussed in detail in the next section. Unless otherwise noted, the stream points to the beginning of the file.
Table 22-7
Members |
the text is stored in |
File does not exist |
Append |
Opens the file, flows to the end of the file, and can only be used in conjunction with enumeration FileAccess.Write |
Create a new file. Can only be used in conjunction with enumeration FileAccess.Write |
Create |
Delete the file, and then create a new file |
Create a new file |
CreateNew |
Throw exception |
Create a new file |
Open |
Open an existing file, and the stream points to the beginning of the file |
Throw exception |
OpenOrCreate |
Open file, stream point to the beginning of the file |
Create a new file |
Truncate |
Open an existing file and clear its contents. Stream points to the beginning of the file, preserving the initial creation date of the file |
Throw 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 of 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:
FileStream afile = File.openread ("Data.txt"); |
Note the following code performs the same function:
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 in the file for the next read and write operation. In most cases, when you open a file, it points to the beginning of the file, but the pointer can be modified. This allows the application to read and write at any location in the file, randomly access the file, or jump directly to a specific location on the file. When working with large files, this is very time-saving because you can immediately navigate to the correct location.
The method to implement this function is the Seek () method, which has two parameters: the first parameter specifies the distance in bytes of the file pointer to move. The second parameter specifies the starting position of the start calculation, represented by a value of the SeekOrigin enumeration. The Seek Origin enumeration consists of 3 values: Begin, Current, and end.
For example, the following line of code moves the file pointer to the 8th byte of the file, where the starting position is the 1th byte of the file:
Afile.seek (8,seekorigin.begin); |
The following line of code moves the pointer forward 2 bytes from the current position. If you execute the following code after the preceding line of code, the file pointer points to the 10th byte of the file:
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 with the Seekorigin.end enumeration value to find the location near the end of the file. The following code looks for the 5th byte in a file:
Afile.seek (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 described later can access the file continuously, and does not allow manipulation of the file pointer in this manner.
2. Reading data
Reading data using the FileStream class is not as easy as reading the data using the StreamReader class described later in this chapter. This is because the FileStream class can handle only raw bytes (raw byte). The ability to process 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 images and sound files. The cost of this flexibility is that you cannot use the FileStream class to read data directly into a string, but you can do so with the StreamReader class. However, 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 the file that the FileStream object points to. This method reads the data from the file and writes the data to an array of bytes. It has three parameters: the first parameter is a byte array that is transmitted in order to accept the data from the FileStream object. The second parameter is the position in the byte array where the data is to begin writing. It is typically 0, which indicates that 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 reading data from a random access file. The file to be read is actually the class file created for this example.
Try: Read data from a random Access file
(1) Create a new console application ReadFile under directory C:\BegVCSharp\Chapter22.
(2) Add the following using directives at the top of the Program.cs file:
Using system;using system.collections.generic;using system.text;using System.IO; |
(3) Add the following code to the main () method:
static void Main (string[] args) { byte[] bydata = new byte[200]; char[] Chardata = new char[200]; Try { FileStream afile = new FileStream ("Http://www.cnblogs.com/Program.cs", FileMode.Open); Afile.seek (135,seekorigin.begin); Afile.read (bydata,0,200); } catch (IOException e) { Console.WriteLine ("An IO exception have 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. As shown in result 22-2.
An example of the description of this application opens its own. cs file for reading. It is used in the following line of code: The string navigates up two directories to find the file:
FileStream afile = new FileStream ("Http://www.cnblogs.com/Program.cs", FileMode.Open); |
The following two lines of code implement find work and read bytes from the file's exact location:
Afile.seek (135,seekorigin.begin); Afile.read (bydata,0,200); |
The first line of code moves the file pointer to the 135th byte of a file. In Program.cs, this is the "N" of namespace; the 135 characters preceding it are the using directive and the associated #region. The second row reads the next 200 bytes 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.
Try { afile.seek (135,seekorigin.begin); Afile.read (bydata,0,100); } catch (IOException e) { Console.WriteLine ("An IO exception have been thrown!"); Console.WriteLine (E.tostring ()); Console.readkey (); return; } |
All operations involved in file IO can throw exceptions of type IOException. All product codes must contain error handling, especially when dealing with file systems. All examples in this chapter have a basic form of error handling.
Once 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 for the System.Text namespace. This class is used to convert raw bytes to more useful items, such as characters:
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 pattern. Then call the GetChars () method, which extracts the byte array and converts it to a character array. When you are finished, you can output the character array to the console.
3. Writing data
The process of writing data to a random access file is very similar to reading data from it. You first need to create a byte array, and the simplest way is to first build an array of characters to write to the file. It then uses the Encoder object to convert it to a byte array, which is very similar to decoder. Finally, the write () method is called to transfer the byte array to the file.
The following builds a simple example to demonstrate its process.
Try: Write data to a random access file
(1) Create a new console application WriteFile in the C:\BegVCSharp\Chapter22 directory.
(2) Add the following using directives at the top of the Program.cs file as shown above:
Using system;using system.collections.generic;using system.text;using System.IO; |
(3) Add the following code to the main () method:
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 have been thrown!"); Console.WriteLine (ex. ToString ()); Console.readkey (); return;} } |
(4) Run the application. It will be closed later.
(5) Navigate to the application directory--the file has been saved in the directory because we have used a relative path. The directory is located in the Writefile\bin\debug folder. Open the Temp.txt file. You can see the text shown in 22-3 in the file.
A description of the example this application opens a file in its own directory and writes a simple string to the file. Structurally, this example is very similar to the previous example, with write () instead of Read () and encoder instead of decoder.
The following line of code uses the ToCharArray () static method of the string class to create a character array. 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 on a string.
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.
Encoder e = Endoding.UTF8.GetEncoder (); E.getbytes (Chardata,0,chardata.length, bydata,0,true); |
This time, you want to create a encoder object based on the UTF8 encoding method. Unicode can also be used for decoding. The character data needs to be encoded in the correct byte format before writing to the stream. You can do this in the GetBytes () method, which converts the character array to a byte array and the character array as the first argument (in this case, Chardata), and the index of the starting position in the array as the second argument (0 represents the beginning of the array). The third argument 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 that begins the write position in the byte array (0 represents the beginning of the Bydata 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 invoke the encoder object later, but it makes little sense when only a single call is made. The last call to encoder must set this parameter 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 straightforward:
Afile.seek (0,seekorigin.begin); Afile.write (bydata,0,bydata.length); |
Like the Read () method, the Write () method has three parameters: the array to write, the array subscript to begin writing, and the number of bytes to write.
C#filestream file read/write (GO)