Home
Search
File HandlingLearn ways to handle files using various methods from the System.IO namespace.
C#
This page was last reviewed on Jan 13, 2022.
File. 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.
Reading and writing. Writing to files can be done with methods like File.WriteAllText. More advanced methods, like StreamReader and StreamWriter, are often better choices.
Directory
FileInfo
Path
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
Step 1 Here we open the file for reading. We use StreamReader in a "using" block—this allows automatic cleanup of resources.
using
Step 2 We call ReadLine. This is a method on StreamReader. It returns null if no further data is available in the file.
ReadLine, ReadLineAsync
Step 3 Here we have the line variable. This contains a line of the file (with no newlines included).
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.
StreamWriter
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.
File.ReadAllText
Tip 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.
File.ReadAllLines
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 lines. We 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.
Line Count
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; } }
Query. 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.
Count
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.
File.ReadLines
Foreach
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.
Note The file is created if it does not exist, or replaced with a new file if it does exist (no appends ever occur).
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.
Argument 1 The first argument to File.AppendAllText is the name of the file we wish to append text to.
Argument 2 The second argument is the string we wish to append to the file—we must add a newline at the end if we want to write a line.
Internals Inspected in IL Disassembler: AppendAllText internally calls StreamWriter, with the second parameter "append" set to true.
Note If the file already exists when the program starts, the file will be appended to. Otherwise, a new file is created.
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 part
first 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.
File.ReadAllBytes
Compress Data
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
Benchmark, 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.
Version 1 In this version of the code, we read in the file with StreamReader line-by-line.
Version 2 Here we read in the file with File.ReadAllLines. The code is more complex and longer.
Result Using 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
Directory. We can manipulate directories on the file system with System.IO. The Directory type, and its static methods, is necessary for this.
Directory
CreateDirectory
Directory.GetFiles
Directory Size
FileInfo. We can get information about a file from the file system with FileInfo. This does not load the entire file into memory. It just reads stored stats.
FileInfo
FileInfo Length
TextReader. The TextReader and TextWriter types form the base class that other, more useful types derive from. Usually they are not useful on their own.
TextReader
TextWriter
Binary. BinaryReader and BinaryWriter make reading or writing a binary file much easier. These types introduce a level of abstraction over the raw data.
BinaryReader
BinaryWriter
Actions. We copy, delete, rename or get time information about files. These actions are available through the File type and the FileInfo type.
File.Copy
File.Delete
File.Exists
File.Move
File.Open
File.Replace
Stream. There are many forms of streams. Sometimes leaving a file on the disk would impact performance or stability in a negative way. In these cases, consider MemoryStream.
Stream
FileStream
MemoryStream
BufferedStream
Seek We can seek to a specific location in a file with the Seek method. Seek is useful with large binary files.
Seek
WebClient. Not every file we want to use is local. A file may be remote. We may need to access the network to download a file from a server.
WebClient
HttpClient
Office. It is common to need to control Microsoft Excel with C# code. We introduce a fast approach. This material may be outdated, but it still helps on many systems.
Excel
Word
CSV files. These are text-based databases. With the System.IO namespace, we can read them into a C# program. Sadly the TextFieldParser is slow.
TextFieldParser
CSV Files
Equality. How can we tell if 2 files are exactly equal? Unfortunately, the file system's metadata is not sufficient. A method that compares each byte is effective.
File Equals
A review. Even with the helpful types provided in .NET, file handling involves many errors. We must account for disk problems and invalid data.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on Jan 13, 2022 (simplify).
Home
Changes
© 2007-2023 Sam Allen.