Hierarchy of streams with basic storages. The FileStream class. The constructors of FileStream class. Instantiating FileStream. Examples. Overview of basic methods
Contents
- 1. Hierarchy of streams with basic storages. Figure
- 2. FileStream class. The purpose. Instantiating the FileStream class. Enumerations FileMode, FileAccess, FileShare, FileOptions
- 3. Examples showing how to create instances of the FileStream type for various use cases
- 3.1. File creation. The simplest case. Example
- 3.2. Opening an already existing file for reading. The simplest case. Example
- 3.3. Examples of processing (writing/reading) a file with the specified type of access. FileShare enumeration
- 3.3.1. Reading data from a file by different (parallel) objects
- 3.3.2. Writing data to a file from various objects. Example
- 3.3.3. An example of writing two numbers to a file and reading them with different objects
- 3.3.4. An example of alternately writing and reading data from one file. Demonstration of FileShare.ReadWrite access
- Related topics
Search other resources:
1. Hierarchy of streams with basic storages. Figure
All classes with basic storages are inherited from the Stream class. The main classes of streams with basic storages are as follows:
- FileStream – provides access to a file. The class supports synchronous and asynchronous writing and reading of information;
- MemoryStream – implements a stream whose basic storage is memory;
- IsolatedStorageFileStream – implements access to a file that is located in isolated storage;
- NetworkStream – provides the main data stream for network access. This class inherits from the FileStream class;
- PipeStream – provides a Stream object for the main pipe that supports both anonymous and named pipes.
Figure 1 shows the classes corresponding to streams with basic stores. Classes are grouped by namespace.
Figure 1. Streams hierarchy with basic storages
In order to use the tools for one or another class, you must first include the corresponding namespace. For example, to use the capabilities of the NetworkStream class at the beginning of the program module, you need to specify the line
using System.Net.Sockets;
⇑
2. FileStream class. The purpose. Instantiating the FileStream class. Enumerations FileMode, FileAccess, FileShare, FileOptions
The FileStream class is used to perform various operations on files. The class contains tools of accessing the file. Some of the methods and properties of the class are inherited from the base Stream class.
The FileStream class supports both synchronous and asynchronous file write and file read operations.
To create an instance of the FileStream class, one of the many constructors of this class must be called. Below is a list of some of them.
public FileStream(string path, System.IO.FileMode mode) public FileStream(string path, System.IO.FileMode mode, System.IO.FileAccess access) public FileStream(string path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share) public FileStream(string path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, int bufferSize) public FileStream(string path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, int bufferSize, bool useAsync) public FileStream(string path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, int bufferSize, System.IO.FileOptions options)
here
- path – path to a file on a disk or other storage medium;
- mode – one of the values of the FileMode enumeration, which determines the file access mode (Open, Append, Create);
- access — specifies access to the file based on the set of constants of the FileAccess enumeration;
- share – defines the type of access control to a file from other objects based on a set of constants from the FileShare enumeration;
- bufferSize is a positive System.Int32 value that defines the size of the buffer in bytes. By default, bufferSize = 4096 bytes;
- useAsync – determines whether synchronous or asynchronous I/O will occur. It should be noted that not all operating systems support asynchronous I/O. If useAsync = true, then asynchronous I/O is provided;
- options – specifies additional configuration options when creating an object of the FileStream type. These options have fixed values and are represented by the FileOptions enumeration.
In the above constructors, the file open mode is set from the set of values of the FileMode enumeration:
- Append – the mode of opening a file to add. This mode can be used in combination with the FileAccess.Write access mode. If the file exists, the file is opened and the file read pointer is rewound to the end of the file. If the file does not exist, a new file is created;
- Create – the mode of creating a new file. This mode is used in combination with FileAccess.Write access. If the file does not exist, then a new file is created at the specified path. If the file exists, it will be overwritten;
- CreateNew – mode, instructs the operating system to create a new file. This mode is used in combination with the FileAccess.Write access modifier. The difference between this mode and FileMode.Create is that if the file already exists, then a System.IO.IOException will be thrown;
- Open – the mode of opening the existing file. Access to a file (read, write, or read/write) is determined by a value from the FileAccess enumeration (see below). If the file does not exist, then a System.IO.FileNotFoundException will be thrown;
- OpenOrCreate – file open mode. If the file does not exist, a new file is created. The file can be opened with any access (FileAccess.Read, FileAccess.Write, FileAccess.ReadWrite);
- Truncate – sets the mode of opening an existing file with its truncation. When the file is open, it should be truncated to zero size. This mode is combined with access to the FileAccess.Write file. If you try to read a file in Truncate mode, a System.ArgumentException will be thrown.
The FileAccess enumeration defines access to a file based on one of the following constants:
- Read – the file is readable;
- ReadWrite – the file is available for writing and reading;
- Write – the file is available for writing.
The FileShare enumeration defines access control for other objects of type FileStream and can have the following values:
- Delete – gives permission to further delete the file;
- Inheritable – indicates that child processes can inherit the file handler;
- None – denies access to the current file. Any request to open the current file will be closed;
- Read – allows further opening of the file for reading. If this value is not specified, then any attempt to open the file for reading from another process will fail until the file is closed;
- ReadWrite – gives permission to further open the file for reading or writing. If this flag is not specified, then any attempt to open a file from the current or another process will fail;
- Write – gives permission to further open the file for writing. If you do not specify this value, then any attempt to open the file for writing from another process (stream) will fail until the file is closed.
The FileOptions enumeration implements additional features (options) that determine the purpose of an open file:
- Asynchronous – indicates that the file can be used for asynchronous reading and writing;
- DeleteOnClose – indicates that the file will be deleted after it is no longer used;
- Encrypted – indicates that the file is encrypted and can only be decrypted using the same user account used for encryption;
- None – indicates that no additional options are applied for the created object of type FileStream;
- RandomAccess — Indicates that the file is being accessed randomly. This hint gives the system a hint to optimize file caching;
- SequentialScan – indicates that the file is being read sequentially from beginning to end. This hint can be used as a hint to the system to optimize file caching. This may provide some performance improvement;
- WriteThrough — instructing the system to write through any intermediate cache and go directly to disk.
⇑
3. Examples showing how to create instances of the FileStream type for various use cases
3.1. File creation. The simplest case. Example
To create a new file, you need to set the file creation mode to FileMode.Create. The peculiarity of this mode is that if the file is present and it is hidden, then an UnauthorizedAccessException will be thrown. Therefore, to create a file, you can write something like the following code:
// Create a new file named "myfile.txt". // If the file already exists, it will be overwritten. try { FileStream fs = new FileStream("myfile.txt", FileMode.Create); // Using file // ... // Close file after use fs.Close(); } catch (UnauthorizedAccessException e) { // Processing if the file is present and it is hidden Console.WriteLine("Error: " + e.Message); }
File creation cannot be with FileAccess.Read access mode. If you write code like this:
... FileStream fs = new FileStream("myfile4.txt", FileMode.Create, FileAccess.Read); ...
then after running, the program will throw a System.ArgumentException.
⇑
3.2. Opening an already existing file for reading. The simplest case. Example
If the file is already on the disk, then to read information from it without modifying it, you need to use the FileMode.Open mode and FileAccess.Read access. If the file is not on disk, then a FileNotFoundException will be thrown. Therefore, you need to catch this exception.
// Opening a file for reading try { FileStream fOpen = new FileStream("myfile5.txt", FileMode.Open, FileAccess.Read); // Read data from file // ... // When finished, close the file fOpen.Close(); } catch (FileNotFoundException e) { // Handle error if file not found Console.WriteLine("Error: " + e.Message); }
⇑
3.3. Examples of processing (writing/reading) a file with the specified type of access. FileShare enumeration
Controlling the accessibility of the file being processed to other instances is defined in the constructor of the FileStream class. The constructor takes as a parameter a value from the FileShare enumeration, which determines how the file is shared from different FileStream instances.
⇑
3.3.1. Reading data from a file by different (parallel) objects
If you want the processed file to be read by another object, then you need to specify FileShare.Read as shown below
// Reading from the same file with different FileStream objects try { // Allow another object to read data from the file "myfile.txt" FileStream fs = new FileStream("myfile.txt", FileMode.Open, FileAccess.Read, FileShare.Read); // Create another object that will read from the same file FileStream fs2 = new FileStream("myfile.txt", FileMode.Open, FileAccess.Read); // Using the file "myfile.txt" by two objects fs and fs2 // ... // Close files after using fs.Close(); fs2.Close(); } catch (UnauthorizedAccessException e) { // Processing if the file is already present and it is hidden Console.WriteLine("Error: " + e.Message); } catch (FileNotFoundException e) { // Обработка, если файл не найден Console.WriteLine("Error: " + e.Message); }
⇑
3.3.2. Writing data to a file from various objects. Example
In order to simultaneously write to a file from various objects, you need to specify FileShare.Write when creating a file object of the FileStream type according to the example below
... // Writing to the file "myfile.txt" by two different objects try { // Indicate that writing to the file "myfile.txt" will be multiple objects - FileShare.Write FileStream fw1 = new FileStream("myfile.txt", FileMode.Open, FileAccess.Write, FileShare.Write); // Create another object that will write to the same file, // be sure to specify FileShare.Write FileStream fw2 = new FileStream("myfile.txt", FileMode.Open, FileAccess.Write, FileShare.Write); // Using the file "myfile.txt" by two objects - writing from two different instances // ... // Close file objects after use fw1.Close(); fw2.Close(); } catch (FileNotFoundException e) { // Processing if file not found Console.WriteLine("Error: " + e.Message); }
⇑
3.3.3. An example of writing two numbers to a file and reading them with different objects
This example demonstrates:
- writing double and int numbers from two different instances of the FileStream class to a file. The offset is taken into account when writing;
- reading from a file numbers of type double and int from two different instances of the FileStream class. As with writing, offset is taken into account;
- capabilities of the BitConverter class for converting various types to byte[] array and vice versa;
- using and combining the Write() and Seek() methods to write data of various types;
- using the ReadByte() method to form an array of type byte[].
using System; using System.IO; using System.Text; namespace ConsoleApp10 { class Program { static void Main(string[] args) { // Writing to the file "myfile.txt" by two different objects try { // Indicate that writing to the file "myfile.txt" will be multiple objects - FileShare.Write FileStream fw1 = new FileStream("myfile.txt", FileMode.Open, FileAccess.Write, FileShare.Write); // Create another object that will write to the same file, // be sure to specify FileShare.Write FileStream fw2 = new FileStream("myfile.txt", FileMode.Open, FileAccess.Write, FileShare.Write); // Using the file "myfile.txt" by two objects - writing from two different instances double d = 288.36; int i = 1230; // Converting to bytes[] arrays byte[] AD = BitConverter.GetBytes(d); byte[] AI = BitConverter.GetBytes(i); // Write a double d from the fs object to a file fw1.Write(AD, 0, AD.Length); // Write to the file the number i of the int type from the fs2 object fw2.Seek(0, SeekOrigin.End); // don't forget for scrolling to the end of the file fw2.Write(AI, 0, AI.Length); // write integer // Close files after using fw1.Close(); fw2.Close(); } catch (UnauthorizedAccessException e) { // Processing if the file is present and hidden Console.WriteLine("Error: " + e.Message); } catch (FileNotFoundException e) { // Processing if file not found Console.WriteLine("Error: " + e.Message); } // Reading from data file by different objects try { // The first object - will read a double FileStream fr1 = new FileStream("myfile.txt", FileMode.Open, FileAccess.Read, FileShare.Read); // Second object - will read an int number from the same file as fr1 FileStream fr2 = new FileStream("myfile.txt", FileMode.Open, FileAccess.Read, FileShare.Read); // Read a double from the fr1 object byte[] AD = new byte[sizeof(double)]; // allocate memory for double type double d; // result // Read byte - method ReadByte (), // instead of a loop, you can also use fr1.Read (AD, 0, AD.Length) for (int i = 0; i < AD.Length; i++) AD[i] = (byte)fr1.ReadByte(); d = BitConverter.ToDouble(AD); Console.WriteLine("d = {0}", d); // Read an int number from another fr2 object int t; byte[] AI = new byte[sizeof(int)]; // Read into array AI, take into account the offset, // fast forward by the size of the double type fr1.Seek(sizeof(double), SeekOrigin.Begin); // consider a number of type int as an array byte[] fr1.Read(AI, 0, AI.Length); // convert byte[] => int t = BitConverter.ToInt32(AI); Console.WriteLine("t = {0}", t); fr1.Close(); fr2.Close(); } catch (FileNotFoundException e) { // Handle error if file not found Console.WriteLine("Error: " + e.Message); } } } }
⇑
3.3.4. An example of alternately writing and reading data from one file. Demonstration of FileShare.ReadWrite access
The example demonstrates the simultaneous writing and reading of an integer from a shared open file. It is assumed that the file has been previously created.
using System; using System.IO; namespace ConsoleApp10 { class Program { static void Main(string[] args) { // Accessing one file from two different instances: // - instance fWrite - writes a number to the file; // - fRead instance - reads the written number from the file and displays it on the screen. try { // Indicate that writing to the file "myfile.dat" will be multiple objects - FileShare.ReadWrite FileStream fWrite = new FileStream("myfile.dat", FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite); // Create another object that will read from the same file, // be sure to specify FileShare.ReadWrite FileStream fRead = new FileStream("myfile.dat", FileMode.Open, FileAccess.Read, FileShare.ReadWrite); // Using the file "myfile.dat" by two objects - fWrite and fRead // The cycle of writing numbers 5, 10, 15 to a file by an object and reading them by another instance byte[] A; // additional array int num; // число, которое нужно написать int offset; // the offset in the file A = new byte[sizeof(int)]; // buffer for one number of type int byte[] A2; for (int i = 0; i < 3; i++) { // 1. Form number num = (i + 1) * 5; // 2. Write number to file "myfile.dat" // 2.1. Converting num => to array byte[] A = BitConverter.GetBytes(num); // 2.2. Calculate the offset to write to the file offset = 0 + i * sizeof(int); // 2.3. Rewind the current write position by offset fWrite.Seek(offset, SeekOrigin.Begin); // 2.4. Write num to the file fWrite.Write(A, 0, A.Length); // 3. Immediately read the written number from the file // 3.1. Allocate memory for a buffer of type byte[], use an additional variable A A2 = new byte[sizeof(int)]; // 3.2. Calculate the offset offset = 0 + i * sizeof(int); // 3.3. Rewind the current read position by offset bytes fRead.Seek(offset, SeekOrigin.Begin); // 3.4. Read number into buffer A2 fRead.Read(A2, 0, A2.Length); // 3.5. Convert byte[] => int int num2 = BitConverter.ToInt32(A2); // 3.6. Display num2 Console.WriteLine("{0} ", num2); } // Close files after using fWrite.Close(); fRead.Close(); } catch (FileNotFoundException e) { // Processing if file not found Console.WriteLine("Error: " + e.Message); } } } }
The result of the program
5 10 15
⇑
Related topics
- Stream concept. Stream architecture in C#. Basic storage streams. Streams with decorators. Adapters streams
- The Stream class. Review of methods. Methods from reading from a stream. Examples
- The Stream class. Operations (methods) of writing to a file stream. Examples
- The Stream class. Stream search methods (operations). Examples
⇑