Opening files in C# involves types from the System.IO
namespace. Methods like File.ReadAllText
can easily read in a file. Often loops are not even needed.
Writing to files can be done with methods like File.WriteAllText
. More advanced methods, like StreamReader
and StreamWriter
, are often better choices.
StreamReader
For text files, StreamReader
and StreamWriter
are often the most useful types. StreamReader
introduces some complexity in our use of the language—we see the "using" statement.
StreamReader
in a "using" block—this allows automatic cleanup of resources.ReadLine
. This is a method on StreamReader
. It returns null
if no further data is available in the file.using System; using System.IO; class Program { static void Main() { // Step 1: open file for reading. using (StreamReader reader = new StreamReader(@"C:\programs\file.txt")) { // Step 2: call ReadLine until null. string line; while ((line = reader.ReadLine()) != null) { // Step 3: do something with the line. Console.WriteLine($"LINE: {line}"); } } } }LINE: Hello my friend LINE: Welcome to the Internet LINE: Third line in file
StreamWriter
This class
writes strings or append strings to a text file. We can write numbers or the textual representation of anything. It also uses a "using" block.
using System.IO; class Program { static void Main() { // Create or open file and write line to it. // ... If file exists, it contents are erased before writing. using (var writer = new StreamWriter(@"C:\programs\example.txt")) { writer.WriteLine("HELLO"); } } }
ReadAllText
This program uses this method to load in the file "file.txt" on the C: volume. Then it prints the contents of the file. The data is now stored in a string
object.
ReadAllText
is the easiest way to put a file into a string
. It is part of the System.IO
namespace.using System; using System.IO; class Program { static void Main() { string file = File.ReadAllText("C:\\file.txt"); Console.WriteLine(file); } }
ReadAllLines
Here we read all the lines from a file and place them in an array. The code reads lines from "file.txt" and uses a foreach
-loop on them. This is efficient code.
using System.IO; class Program { static void Main() { // Read in every line in specified file. // ... This will store all lines in an array in memory. string[] lines = File.ReadAllLines("file.txt"); foreach (string line in lines) { // Do something with the line. if (line.Length > 80) { // Important code. } } } }
Count
linesWe count the number of lines in a file with few lines of code. The example here is a bit slow. But it works. It references the Length
property.
using System.IO; class Program { static void Main() { // Another method of counting lines in a file. // ... This is not the most efficient way. // ... It counts empty lines. int lineCount = File.ReadAllLines("file.txt").Length; } }
Does a line containing a specific string
exist in the file? Maybe we want to see if a name or location exists in a line in the file. We use LINQ to find any matching line.
using System.IO; using System.Linq; class Program { static void Main() { // See if line exists in a file. // ... Use a query expression to count matching lines. // ... If one matches, the bool is set to true. bool exists = (from line in File.ReadAllLines("file.txt") where line == "Some line match" select line).Count() > 0; } }
ReadLines
This method does not immediately read in every line. It instead reads lines only as they are needed. We use it in a foreach
-loop.
using System; using System.IO; class Program { static void Main() { // Read lines in file 1-by-1. foreach (string line in File.ReadLines(@"C:\programs\file.txt")) { Console.WriteLine("LINE: {0}", line); } } }LINE: Hello my friend LINE: Welcome to the Internet ...
WriteAllLines
We can write an array to a file. When we are done within-memory processing, we often need to write the data to disk.
using System.IO; class Program { static void Main() { // Write a string array to a file. string[] stringArray = new string[] { "cat", "dog", "arrow" }; File.WriteAllLines("file.txt", stringArray); } }cat dog arrow
WriteAllText
A simple method, File.WriteAllText
receives two arguments. It receives the path of the output file, and the exact string
contents of the text file.
using System.IO; class Program { static void Main() { File.WriteAllText("C:\\perls.txt", "Dot Net Perls"); } }
AppendAllText
We could read in a file, append to that in memory, and then write it out completely again. That is slow. Its more efficient to use an append.
File.AppendAllText
is the name of the file we wish to append text to.string
we wish to append to the file—we must add a newline at the end if we want to write a line.AppendAllText
internally calls StreamWriter
, with the second parameter "append" set to true.using System.IO; class Program { static void Main() { // Use AppendAllText to write one line to the text file. File.AppendAllText("C:\\perls.txt", "first part\n"); // The file now has a newline at the end, so write another line. File.AppendAllText("C:\\perls.txt", "second part\n"); // Write a third line. string third = "third part\n"; File.AppendAllText("C:\\perls.txt", third); } }first part second part third partfirst part second part third part first part second part third part
ReadAllBytes
We use File.ReadAllBytes
to read an image into memory. Here we read the bytes from a WEBP file into a byte
array, and print its length and the first byte
.
using System; using System.IO; class Program { static void Main() { // Read in a binary file. byte[] webpFile = File.ReadAllBytes(@"C:\programs\test.webp"); Console.WriteLine("Length: {0}", webpFile.Length); Console.WriteLine("First byte: {0}", webpFile[0]); } }Length: 822 First byte: 82
ReadLine
Suppose we have a text file with many lines—possibly 1 million lines. We could use a method like ReadAllLines
, or StreamReader
on the file.
StreamReader
line-by-line.File.ReadAllLines
. The code is more complex and longer.ReadLine
with StreamReader
is faster. For files with many lines, it is worth reading in the lines iteratively.using System; using System.Diagnostics; using System.IO; class Program { static void CreateFileWithManyLines() { // Create temporary file for benchmark. using (StreamWriter writer = new StreamWriter(@"C:\programs\file.txt")) { for (int i = 0; i < 1000000; i++) { writer.WriteLine("x"); } } } const int _max = 10; static void Main() { CreateFileWithManyLines(); // Version 1: use StreamReader and read in each line. var s1 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { if (Method1() == 0) { return; } } s1.Stop(); // Version 2: use File.ReadAllLines to get entire string array. var s2 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { if (Method2() == 0) { return; } } s2.Stop(); Console.WriteLine( s1.Elapsed.TotalMilliseconds.ToString("0.00 ms")); Console.WriteLine( s2.Elapsed.TotalMilliseconds.ToString("0.00 ms")); } static int Method1() { int count = 0; using (StreamReader reader = new StreamReader(@"C:\programs\file.txt")) { while (true) { string line = reader.ReadLine(); if (line == null) { break; } count++; } } return count; } static int Method2() { string[] array = File.ReadAllLines(@"C:\programs\file.txt"); return array.Length; } }219.53 ms StreamReader, ReadLine 1212.43 ms File.ReadAllLines
Even with the helpful types provided in .NET, file handling involves many errors. We must account for disk problems and invalid data.