How to read from file in C#
The ability to read from file gives our C# programs the ability to act on data given by other programs, which may be written in different programming languages.
Such a ability is also helpful in allowing humans to configure how our C# program will behave at runtime.
Since being able to read from file is so helpful in C#, I want to remember how I can do that with this post.
Specifying file access
For file reads, we must use either the Read
or the ReadWrite
member of the System.IO.FileAccess
enumeration to specify read access.
Specifying file mode
Apart from specifying file access, we specify the file mode via one of the members of the System.IO.FileMode
enumeration. The file mode determines how the operating system will open the file for our code to read from.
Getting an instance of System.IO.FileStream
As with writing to file, there are a few ways which we can get code access to the file that we want to read from.
-
Using the
System.IO.FileStream
constructors.FileStream fileStream = new FileStream("techcoil.txt", FileMode.Open, FileAccess.Read);
-
Using the static
Open
method ofSystem.IO.File
class.FileStream fileStream = File.open("techcoil.txt", FileMode.Open, FileAccess.Read);
-
Using the
Open
method of theSystem.IO.FileInfo
class.FileInfo fileInfo = new FileInfo("techcoil.txt"); FileStream fileStream = fileInfo.Open(FileMode.Open, FileAccess.Read);
The above code segments attempt to open techcoil.txt. If techcoil.txt does not exists, an instance of System.IO.IOException will be thrown.
Personally, I prefer using the last method as the FileInfo
instance can provide me with useful information about the file. For instance, I can check whether the file exists before I attempt to gain code access to the file:
FileInfo fileInfo = new FileInfo("techcoil.txt"); // Check whether techcoil.txt exists if (fileInfo.Exists) { FileStream fileStream = fileInfo.Open(FileMode.Open, FileAccess.Read); // Use fileStream to read data from file... } else { Console.WriteLine("techcoil.txt does not exists."); }
Reading text from file
Assuming that we want to read text from techcoil.txt and output the contents to console. The following code segment demonstrates how we can do this.
public class ReadTextFromFile { public static void Main(string[] args) { try { FileInfo fileInfo = new FileInfo("techcoil.txt"); // If techcoil.txt exists if (fileInfo.Exists) { // Get an instance of FileStream that represents // techcoil.txt FileStream fileStream = fileInfo.Open(FileMode.Open, FileAccess.Read); // Encapsulate the file stream instance in a StreamReader // instance StreamReader reader = new StreamReader(fileStream); String line; // Read the file, line by line while ((line = reader.ReadLine()) != null) { // Print out the line to console Console.WriteLine(line); } // end while reader.Close(); } else { Console.WriteLine("techcoil.txt does not exist."); } // end if } catch (IOException ioe) { Console.WriteLine(ioe); } // end try-catch } // end public static void Main(string[] args) } // end class public class ReadTextFromFile
The code segment starts by checking whether techcoil.txt exists. If it exists, an instance of the FileStream
class is created via the FileInfo
instance. The FileStream
instance is then encapsulated in a System.IO.StreamReader
instance, which is capable of reading text.
When the code is able to get read access to the file, the while loop reads the contents of the file and output to the console, line by line. When there are no more lines to read, reader.ReadLine
returns null.
Reading binary data from file
We can use the Read
method from the FileStream
instance to read binary data from the file. Let's demonstrate this through a file copy example.
public class ReadBinaryDataFromFile { public static void Main(string[] args) { try { FileInfo fileInfo = new FileInfo("techcoil.txt"); if (fileInfo.Exists) { byte[] buffer = new byte[1024]; // Get read access to file to copy from FileStream srcFileStream = new FileStream("techcoil.txt", FileMode.Open, FileAccess.Read); // Get write access to new file to copy to FileStream destFileStream = new FileStream("techcoil_new.txt", FileMode.Create, FileAccess.Write); int bytesRead; while((bytesRead = srcFileStream.Read(buffer, 0, buffer.Length)) != 0) { Console.WriteLine("File copying in progress"); // Write the bytes read to new file destFileStream.Write(buffer, 0, bytesRead); } // end while srcFileStream.Close(); destFileStream .Close(); } else { Console.WriteLine("techcoil.txt does not exist"); } // end if } catch (IOException ioe) { Console.WriteLine(ioe); } // end try-catch } // end public static void Main(string[] args) } // end public class ReadBinaryDataFromFile
The code segment starts by checking the existence of techcoil.txt - the source file to copy data from. If techcoil.txt exists, a 1024-sized byte array is set aside to hold data during file reads. Two FileStream
instances are then created, one having read access to techcoil.txt; the other having write
access to techcoil_new.txt - the destination file to copy data to. When both the files can be accessed for reading and writing, the program proceeds on with copying data from techcoil.txt to techcoil_new.txt.
In the while loop, srcFileStream.Read
populates buffer
with data, starting from the first element position (at index 0) to the last element position, where possible. It returns the number of bytes copied to buffer.
Some reflects about this post
Why do we use Console.WriteLine
instead of Console.Write
to output the content read by reader.ReadLine
?
The ReadLine
method will remove the new line character that denotes the end of line. By using Console.WriteLine
, we put back the new line character onto the console screen.
Instead of getting a FileStream
instance, can we get a StreamReader
instance directly?
Yes, there are a couple of ways to get a StreamReader
instance directly.
- Use the
OpenText()
method of thefileInfo
instance.FileInfo fileInfo = new FileInfo("techcoil.txt"); StreamReader reader = fileInfo.OpenText();
- Use the static
OpenText()
method of theFile
class.StreamReader reader = File.OpenText("techcoil.txt");
-
Use the
StreamReader
constructorStreamReader reader = new StreamReader("techcoil.txt");
Instead of manually doing binary data file copy, is there a shorter way to perform file copy?
Yes, we can use the System.IO.File.Copy method to perform the file copy:
File.Copy("techcoil.txt", "techcoil_new.txt", true);
The above code segment will copy the contents of techcoil.txt to techcoil_new.txt. A true value given as the third parameter indicates that if techcoil_new.txt exists, it's content will be overridden.
Why do we bother with manually copying the binary data file when there is a fast and easy way of doing so?
One reason for doing so is when it is necessary to provide feedback to the file copying progress to user, especially when copying very large file. Another situation that I could recall was trying to send a large multipart HTTP request to a server endpoint. By performing the binary read directly, I can show my user how many bytes had been read from file and how many bytes had been sent to the HTTP server endpoint.