Files & Folders
One of the ways of permanent storage of data is through files. A file is a collection of data stored on a secondary storage device, such as the Hard Disk. Every file has a name associated with it, such as Essay.txt. The name comprises of two parts the base name (in our case ‘Essay’) and the extension (txt). The portion before the period (.) is the base name whereas the one after it is the extension. A file name can also contain multiple periods – Dr. No.avi. The most significant period is always the last one. So, in this case, the base name of the file would be Dr. No and the extension avi.
The extension is what determines the type of the file. For example, a document has an extension of doc while a JPEG Image file has an extension of jpg. The base name is what we specify to identify that particular file.
Files are contained in folders or directories. A directory itself can contain other files and folders, thus forming a hierarchy. Files within a folder (directory) need to have unique names. Files with same base name but different extensions are allowed. So, the file My File.txt and My File.doc can co-exist in a folder. The full path of the file marks its complete address on a machine. For instance, if the file Notepad.exe is contained inside the Windows directory of your C drive, its path would be “C:\Windows\Notepad.exe”. Likewise, if it were to be contained inside the System32 directory which in turn is present in the Windows directory, the full path would be “C:\Windows\System32\Notepad.exe”.
Note: No two files on your computer can have the same full path.
Stream
A stream is a sequence of bytes travelling from a source to a destination over a communication medium. Streams can either be input or output. The input stream is used for reading while the output stream is used for writing.
Note: This stream concept does not just apply to files. It holds true for communication over a network through sockets too.
File System Classes
.NET provides a lot of classes for handling files. These are contained in the System.IO namespace. Listed below are various classes under this namespace.
Class Name | Description |
---|---|
FileStream | Is used to read from and write to any location within a file. |
BinaryReader | Is used to read primitive data types in the form of binary data from the stream. |
StreamReader | Is used to read characters from a byte stream. |
StringReader | Is used to read data from a string buffer. |
BinaryWriter | Is used to write primitive data types in the form of binary data to the stream. |
StreamWriter | Is used to write characters to a byte stream. |
StringWriter | Is used to write data to a string buffer. |
BinaryReader | Is used to read primitive data types in the form of binary data from the file stream. |
StreamReader | Is used to read characters from the a byte stream. |
DirectoryInfo | Is used to perform operations on directories. |
FileInfo | Is used to perform operations on files. |
FileStream Class
The FileStream class resides under the System.IO namespace and is derived from the abstract class Stream. It supports random access through seeking. Before you begin reading from and writing to a file, an object of the FileStream class needs to initialized. The parameterized constructor of this class allows to create/open files and set up appropriate file sharing modes.
Creating a new file.
FileStream fs = new FileStream ( "TestFile.txt", FileMode.Create, FileAccess.Write, FileShare.Read ); |
Note: The code is spanned across multiple lines for the sake of clarity.
The first parameter to the constructor is the path to the file. In this case the new file will be created in the working directory of the application. A complete path such as C:\Program Files\Maxotek\Tutorials\C-Sharp\Lesson14\TestFile.txt can also be used. Backslash being the escape sequence starter would need to be escaped in the string. The code would look something like:-
FileStream fs = new FileStream ( "C:\\Program Files\\Maxotek\\Tutorials\\C-Sharp\\Lesson14\\TestFile.txt", FileMode.Create, FileAccess.Write, FileShare.Read ); |
Another way of doing this, is to use the @ character before the string. This prevents any escape sequence character as the backslash itself is taken as a normal character.
FileStream fs = new FileStream ( @"C:\Program Files\Maxotek\Tutorials\C-Sharp\Lesson14\TestFile.txt", FileMode.Create, FileAccess.Write, FileShare.Read ); |
The second parameter to the constructor is the FileMode enumeration. It can have any of the following values.
File Mode | Description |
---|---|
Create | Creates a new file or truncates the existing file. |
CreateNew | Creates a new file. If the file already exists, throws a System.IO.IOException. |
Open | Opens an existing file. Throws a System.IO.FileNotFoundException if the file does not exist. |
OpenOrCreate | Opens an existing file or creates a new one. The difference between this mode and the Create mode is that it does not truncate the file. |
Append | Opens the file and seeks to the end. A new file is created if the file does not exist. |
Truncate | Opens an existing file and truncates its content so that the file size becomes zero. Attempting to read in this mode throws an exception. |
The third parameter is the FileAccess which specifies whether the file is to be opened for Reading (FileAccess.Read), Writing (FileAccess.Write) or both (FileAccess.ReadWrite).
The last parameter is FileShare mode which states how the file will be shared.
FileShare Mode | Description |
---|---|
Read | Allows other handles to read from the file. |
Write | Allows other handles to write to the file. |
Delete | Allows subsequent deleting of the file. |
Inheritable | Makes the file handle inheritable to child processes. |
None | Declines sharing of file. No other process can open the file until it is closed. |
Note: The constructor is overloaded into many other forms which take various other types and combinations of parameters. The above form was one of the basic ones.
Writing to the File
We use the StreamWriter class which is inherited from the abstract class TextWriter to write a series of characters. After opening the file in the appropriate mode (Write or ReadWrite in this case), a new object of the StreamWriter class is created. The object of the FileStream class is passed to it, thus associating the stream with the file. After this, the content can be written to the file by using the Write or the WriteLine method. WriteLine appends an end of line to the content. These two methods are highly overloaded to enable almost all built in data types to be directly written.
Once you have done all the writing, make sure you close the file using the Close method. This ensures all the content is physically written to the file. For performance reasons, the write operation is buffered and sometimes the content might not be physically written to the file even after the Write method was called. To force all the buffers to be cleared and all buffered content to be written to the underlying stream (File in our case), use the Flush method.
1 2 3 4 5 6 7 8 9 10 11 12 | FileStream fs = new FileStream ( "TestFile.txt", FileMode.Create, FileAccess.Write, FileShare.Read ); StreamWriter sw = new StreamWriter(fs); sw.Write("Hello World"); sw.Close(); // Close the Stream fs.Close(); // Close the File |
Reading from a fie
The StreamReader class is used to read a series of characters from a FilStream. This class is derived from the abstract class TextReader. Before reading, the file must be opened in the appropriate mode (Read or ReadWrite). To Read the next character or the next set of characters, use the Read method. This method has two forms. One that does not take any parameters and reads the next character. It returns the byte value of the character. The other one takes three parameters:-
- An array of characters – The read characters are stored in the variable passed here.
- The index of the buffer at which to begin writing
- Maximum number of characters to read
The ReadLine method reads a line of characters and returns the result in the form of a string.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | FileStream fs = new FileStream ( "TestFile.txt", FileMode.Open, FileAccess.Read, FileShare.Read ); StreamReader sr = new StreamReader(fs); string str = sr.ReadLine(); while (str != null) { Console.WriteLine(str); str = sr.ReadLine(); } sr.Close(); // Close the Stream fs.Close(); // Close the File |
The file pointer can be seeked to any position of the file using the BaseStream property’s Seek method. This method takes two parameters. The first, a byte offset relative to the Origin (second) parameter. This value can be either positive which moves the pointer down the file or negative which moves the file pointer upwards. The second parameter known as the Origin parameter indicates the reference point to obtain the new position. The permissible values are Begin, Current and End.
The following line of code moves the file pointer to the 5th character from the beginning.
sr.BaseStream.Seek(5, SeekOrigin.Begin); |
Moves the pointer to the start.
sr.BaseStream.Seek(0, SeekOrigin.Begin); |
Moves the pointer to 5 characters ahead of the current position.
sr.BaseStream.Seek(5, SeekOrigin.Current); |
Moves the pointer 5 characters backward from the current position.
sr.BaseStream.Seek(-5, SeekOrigin.Begin); |
Moves the pointer to the end.
sr.BaseStream.Seek(0, SeekOrigin.End); |
The Peek method is used to read the next character without consuming it, i.e the file pointer does not move ahead.
Implementing Binary Read & Write
The StreamReader and StreamWriter classes work with character data. In this mode everything is written as plain text. To implement binary operations, wherein a number such as 327.68 would be written as a float value consuming four bytes and not just as plain text, we need to use the BinaryReader and BinaryWriter classes.
They are very similar to their text counterparts except that no Line (ReadLine and WriteLine) methods are provided. The BinaryReader class also supports data type specific methods such as ReadInt32, ReadDouble, etc. These allow you to directly read the content from the file in the appropriate format. If we were to use the StreamReader class, we would have to convert the string to integer or double format using the Convert.ToInt32 and Convert.ToDouble methods.
Writing to File
1 2 3 | int MyNumber = 69; BinaryWriter bw = new BinaryWriter(fs); bw.Write(MyNumber); |
Reading from file
1 2 | BinaryReader br = new BinaryReader(fs); int MyNumber = br.ReadInt32(); |
Implementing the Windows File System
Often we need to browse directories and locate files. Many such operations can be accomplished by using the two classes – DirectoryInfo and FileInfo. Both of these are derived from the FileSystemInfo class.
The tables below list some of the commonly used properties and methods corresponding to both of these classes.
Properties of DirectoryInfo Class
Property | Description |
---|---|
Attributes | Gets or sets attributes associated with the current directory. |
CreationTime | Gets or sets the Creation time of the directory. |
Exists | Gets a Boolean value indicating whether the directory exists |
FullName | Gets a string containing the full path of the directory. |
LastAccessTime | Gets the last accessed time of the directory. |
Name | Gets a string containing the name of the directory. |
Methods of DirectoryInfo Class
Method | Description |
---|---|
Create | Creates a directory. |
Delete | Deletes a directory. |
GetDirectories | Returns the directories in the current directory. Supports filtering and recursive listing. |
GetFiles | Returns the file in the current directory. |
Properties of FileInfo class
Property | Description |
---|---|
Attributes | Gets or sets the attributes associated with the current file. |
CreationTime | Gets or sets the CreationTime of the file. |
Directory | Gets an instance of the directory to which the file belongs to. |
Exists | Gets a Boolean value indicating whether the file exists. |
Extension | Gets a string containing the extension of the file. |
FullName | Gets a string containing the full path to the file. |
LastAccessTime | Gets the last access time of the file. |
LastWriteTime | Gets the time of the last wriiten activity on the file. |
Length | Gets the length of the file in Bytes. |
Name | Gets the name of the File. |
Methods of FileInfo class
Method | Description |
---|---|
Create | Creates a new file. |
AppendText | Appends a text to the file. |
Delete | Deletes the file. |
Open | Opens the file. |
OpenRead | Opens a file in the read-only mode. |
Creating Objects
Creating a DirectoryInfo or FileInfo object is very simple. The constructor takes the path to the file.
DirectoryInfo di = new DirectoryInfo("C:\\Windows"); FileInfo fi = new FileInfo("C:\\Windows\\Notepad.exe"); |
Listing All Files in a Directory
The following code snippet lists all the files in the C:\Windows directory.
1 2 3 4 5 6 | DirectoryInfo di = new DirectoryInfo("C:\\Windows"); FileInfo[] fis = di.GetFiles(); foreach (FileInfo fi in fis) { Console.WriteLine(fi.Name); } |