File operations in .NET: Create, Read, Update, Delete, and Search

.NET has a good, high-level File API that abstracts away the complexity of file operations. You can create, read, update, delete, and search for files with a single method call.

It’s flexible and provides multiple approaches, allowing you to pick the best tool for the job. For example, you can load an entire file all at once, or stream it into memory line-by-line. In most cases, you can choose between synchronous and asynchronous approaches.

This article shows how to do the different file operations – create, read, update, delete, and search – including the different approaches.

Create a new text file

You can use System.IO.File.WriteAllText() to create a new text file like this:

StringBuilder sb = new StringBuilder(); sb.AppendLine("We the People of the United States, "); sb.AppendLine("in Order to form a more perfect Union, "); sb.AppendLine("establish Justice, insure domestic Tranquility, "); sb.AppendLine("provide for the common defense, promote the general Welfare, "); sb.AppendLine("and secure the Blessings of Liberty to ourselves and our Posterity, "); sb.AppendLine("do ordain and establish this Constitution for the United States of America."); var constitution = sb.ToString(); System.IO.File.WriteAllText(path: @"C:\temp\AmericanConstitution.txt", contents: constitution);

The async version is System.IO.File.WriteAllTextAsync().

static async Task Main(string[] args) { await System.IO.File.WriteAllTextAsync(path: @"C:\temp\hello.txt", contents: "hello world"); }

Note: If the file exists already, it overwrites it.

Read a text file all at once

If your file is small, then you can read it into memory all at once. You can either read all of the text into a single string, or load each line as a string in an array.

Read all of the text into a single string

To read a text file into a string, use System.IO.File.ReadAllText(), like this:

var constitution = System.IO.File.ReadAllText(path: @"C:\temp\AmericanConstitution.txt"); Console.WriteLine(constitution);

The async version is System.IO.File.ReadAllTextAsync().

static async Task Main(string[] args) { var hello = await System.IO.File.ReadAllTextAsync(path: @"C:\temp\hello.txt"); }

Read all of the text with each line as a string in an array

To load the text file into a string array, where each line is a separate string in the array, use System.IO.File.ReadAllLines() like this:

var constitution = System.IO.File.ReadAllLines(path: @"C:\temp\AmericanConstitution.txt"); foreach(var line in constitution) { Console.WriteLine(line); }

The async version is System.IO.File.ReadAllLinesAsync().

var helloLines = await System.IO.File.ReadAllLinesAsync(path: @"C:\temp\hello.txt"); foreach(var line in helloLines) { Console.WriteLine(line); }

Read a text file line by line

This approach streams the file into memory line by line, instead of reading it all at once. Use this approach if you’re reading a big file (to avoid OutOfMemoryException) or if you’re doing a forward-only read (where you only care about one line at a time, and don’t need the line to stick around after).

Use System.IO.File.ReadLines() to read a file line by line in a streaming manner. This is a nice, high-level method that abstracts away the fact that it’s using a StreamReader.

foreach(var line in System.IO.File.ReadLines(path: @"C:\temp\AmericanConstitution.txt")) { Console.WriteLine(line); }

There’s not a simple, direct async version of ReadLines(). It doesn’t make sense to read individual lines in an asynchronous manner. I can’t see a reason why you’d want to do that, and there’s definitely a performance hit involved. However, if you really want to read lines asynchronously, you could try using StreamReader.

Update a text file by appending to the end

You can use System.IO.File.AppendAllText() to append to the end of a file.

StringBuilder sb = new StringBuilder(); sb.AppendLine("Article 1"); sb.AppendLine("Section 1"); sb.AppendLine("All legislative Powers herein granted shall be vested in a Congress of the United States, "); sb.AppendLine("which shall consist of a Senate and House of Representatives."); var constitution = sb.ToString(); System.IO.File.AppendAllText(path: @"C:\temp\AmericanConstitution.txt", contents: constitution);

The async version is System.IO.File.AppendAllTextAsync().

static async Task Main(string[] args) { await System.IO.File.AppendAllTextAsync(path: @"C:\temp\hello.txt", contents: "bye"); }

Note: If the file doesn’t exist, this creates it.

How do I insert anywhere in the file?

You may be wondering, how do I insert text anywhere, instead of just appending to the end of the file? For example, you may want to prepend text to the beginning of the file, or modify text in the middle of the file.

There’s no simple, high-level API call that allows you to do this.

Files are like arrays. If you wanted to insert a new element into the middle of the array, you’d have to shift all elements to the right by one. It’s the same concept with files. You have to shift all the existing data to be able to insert anywhere in the file. This becomes especially difficult if you’re dealing with big files. This algorithm will be the subject of a future article.

Delete a text file

You can use System.IO.File.Delete() to delete a file. This is straightforward:

System.IO.File.Delete(path: @"C:\temp\AmericanConstitution.txt");

There’s no async version of this.

Searching for files in a directory

You can use System.IO.Directory.EnumerateFiles() to search for files in a directory. This has many overloads, allowing you specify exactly what you want. You can search the current directory only, search all subdirectories, filter files by name (including extension), and filter by attributes. Here are a few scenarios.

Get all files in a directory

This returns all files in the top-level directory.

foreach (var file in System.IO.Directory.EnumerateFiles(@"C:\temp\")) { Console.WriteLine(file); }

Get all files in the directory and all subdirectories

This returns all files from the specified directory and all of its subdirectories.

foreach (var file in System.IO.Directory.EnumerateFiles(@"C:\temp\", "*", SearchOption.AllDirectories)) { Console.WriteLine(file); }

Get all JSON files in the directory

You can apply a search pattern that allows you filter files by name and extension. The following searches for all files with the .json extension.

foreach (var file in System.IO.Directory.EnumerateFiles(@"C:\temp\", "*.json")) { Console.WriteLine(file); }

Get all files that aren’t read-only

You can pass in an EnumerationOptions object to filter out files based on attributes. For example, the following searches for all JSON files, filtering out ones that are read-only.

foreach (var file in System.IO.Directory.EnumerateFiles(@"C:\temp\", "*.json", new EnumerationOptions() { AttributesToSkip = FileAttributes.ReadOnly })) { Console.WriteLine(file); }

AttributesToSkip is an enum flag, so you can OR together all the attributes that you want to filter out. For example, let’s say you want to filter out hidden files and read-only files. You’d use the following:

new EnumerationOptions() { AttributesToSkip = FileAttributes.ReadOnly | FileAttributes.Hidden }

Leave a Comment