There are three ways to update a file’s content:
- Append to the end of the file.
- Read all the content, make changes, then overwrite the file with the changed content.
- Read one line at a time, make changes and write to a temp file, then rename the temp file to overwrite the file.
Which option you pick depends on the file’s format and size. For example, if you’re writing to an existing CSV file, you’d append new lines to the end of the file. If you’re updating a JSON file, you’d read all the JSON content, make changes, then write it all at once back to the file (option 2).
You can use high-level methods from the .NET File API (in System.IO) to update the file – such as File.AppendAllText(). Here’s an example of a few ways to append to a file:
using System.IO;
//Append string as-is to the end of the file
File.AppendAllText(@"C:\temp\a.txt", "Hello World");
//Append strings on new lines to the end of the file
File.AppendAllLines(@"C:\temp\b.txt", new List<string>()
{
"Jurassic Park",
"The Matrix"
});
//Async equivalents
await File.AppendAllTextAsync(@"C:\temp\a_async.txt", "Hello World Async");
await File.AppendAllLinesAsync(@"C:\temp\b_async.txt", new List<string>()
{
"Hello",
"World"
});
Code language: C# (cs)
Note: If the file doesn’t exist, these append methods will create it and then write to it.
In this article, I’ll show the other two ways to update a file’s contents besides appending to the end of the file.
Read all content, make changes, and then overwrite the file
Appending to a file is simple, but what if you need to change or insert content in the middle of the file? The simplest option is to read the entire file’s contents, make the desired changes, and then overwrite the file with the changed content. You can use File.WriteAllText() to overwrite a file instead of appending to it.
Here’s an example. Let’s say you want to modify the contents of a JSON file. This reads and deserializes the file’s JSON contents, modifies a value, and then serializes it back to JSON and overwrites the file:
using System.IO;
using System.Text.Json;
//1 - Read the file's contents
var json = File.ReadAllText(@"C:\temp\person.json");
var person = JsonSerializer.Deserialize<Person>(json);
//2 - Make the change
person.Name = "Robert";
//3 - Overwrite the file with the changes
var changedJson = JsonSerializer.Serialize(person, new JsonSerializerOptions() { WriteIndented = true });
File.WriteAllText(@"C:\temp\person.json", changedJson);
Code language: C# (cs)
Note: There are various ways to read a JSON file, such as deserializing it as a stream.
Here’s another example. Let’s say you want to make all of the text in a file lowercase. To do that, read the entire file to a string, use ToLower(), and then overwrite the file with the lowercased string:
using System.IO;
//1 - Read the file's entire contents
var words = File.ReadAllText(@"C:\temp\words.txt");
//2 - Make the change
var lowercaseWords = words.ToLower();
//3 - Overwrite the file
File.WriteAllText(@"C:\temp\words.txt", lowercaseWords);
Code language: C# (cs)
Read one line at a time, make changes, write to a temp file
If you’re dealing with a big file, you may not want to load all of its contents into memory at once. Instead, you can read the file one line at a time, make changes, and write the changes to a temp file. At the end, you can rename the temp file to overwrite the original file. You can do this using a combination of File.ReadLines(), StreamWriter, and File.Move(). This is far simpler than attempting to read/write to one file stream at the same time.
Here’s an example. Let’s say you want to insert a line at the beginning of a file. The following code shows how to do this:
using System.IO;
var originalFile = @"C:\temp\movies.csv";
var tempFile = originalFile + ".tmp";
using (var writer = File.CreateText(tempFile))
{
writer.WriteLine("Title,Year");
foreach(var line in File.ReadLines(originalFile))
{
//This is where you'd make changes to the line if necessary
writer.WriteLine(line);
}
}
File.Move(tempFile, originalFile, overwrite: true);
Code language: C# (cs)
Note: StreamWriter writes to an in-memory buffer and flushes it to disk when it gets full. You can change StreamWriter’s buffer size if necessary.