C#: Read Text and JSON File Contents into Variable in Memory

Jun 18, 2024  • C#

Whether you’re building a C# console app, a web service, or some other project, reading the contents of a file is a common task performed. This article will provide you with the basics necessary to do just this.

Read File using File.ReadAllText

The simplest way to read a file into a string is by using File.ReadAllText. This method reads all lines of the file into a single string.

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string filePath = "sample.txt";
        try
        {
            string fileContents = File.ReadAllText(filePath);
            Console.WriteLine(fileContents);
        }
        catch (IOException e)
        {
            Console.WriteLine($"An error occurred: {e.Message}");
        }
    }
}

This method is straightforward and works well for small to moderately sized files. It’s not optimal for very large files, as it reads the entire file into memory at once.

Read File using StreamReader

For more control over the reading process, StreamReader is a great choice. It allows you to read the file line-by-line or even character-by-character.

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string filePath = "sample.txt";
        try
        {
            using StreamReader reader = new StreamReader(filePath);
            string fileContents = reader.ReadToEnd();
            Console.WriteLine(fileContents);
        }
        catch (IOException e)
        {
            Console.WriteLine($"An error occurred: {e.Message}");
        }
    }
}

Using StreamReader can be more efficient than File.ReadAllText for large files, as it doesn’t load the entire file into memory at once. It provides flexibility to read in chunks or line-by-line, making it useful for processing large datasets.

Read File Asynchronously

With asynchronous programming becoming a norm, reading files asynchronously can improve the performance of your application, especially when dealing with I/O operations.

using System;
using System.IO;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        string filePath = "sample.txt";
        try
        {
            using StreamReader reader = new StreamReader(filePath);
            string fileContents = await reader.ReadToEndAsync();
            Console.WriteLine(fileContents);
        }
        catch (IOException e)
        {
            Console.WriteLine($"An error occurred: {e.Message}");
        }
    }
}

The ReadToEndAsync method is part of asynchronous file operations in .NET. It frees up the main thread, allowing your application to remain responsive while waiting for the file operation to complete.

Read Structured JSON File using System.Text.Json

Reading JSON files is an essential skill in modern C# development. Whether you’re dealing with configuration files, data interchange, or logging, JSON is ubiquitous. Let’s look at using the System.Text.Json namespace to read JSON files into C# objects efficiently and effectively.

Let’s start with a simple JSON file named data.json:

{
    "name": "John Doe",
    "age": 30,
    "isEmployed": true,
    "skills": ["C#", "JavaScript", "SQL"]
}

Next, create a Person class that matches the structure of your JSON data:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public bool IsEmployed { get; set; }
    public List<string> Skills { get; set; }
}

Now, we will read the JSON file and deserialize it into a Person object using System.Text.Json:

using System;
using System.IO;
using System.Text.Json;

class Program
{
    static void Main()
    {
        string filePath = "data.json";
        try
        {
            string jsonString = File.ReadAllText(filePath);
            Person person = JsonSerializer.Deserialize<Person>(jsonString);

            Console.WriteLine($"Name: {person.Name}");
            Console.WriteLine($"Age: {person.Age}");
            Console.WriteLine($"Is Employed: {person.IsEmployed}");
            Console.WriteLine("Skills: " + string.Join(", ", person.Skills));
        }
        catch (Exception e)
        {
            Console.WriteLine($"An error occurred: {e.Message}");
        }
    }
}

This approach reads the entire file content as a string and then deserializes it into a Person object. Simple and effective for small to medium-sized files.

Read Dynamic JSON File using System.Text.Json

Sometimes, you don’t have a predefined class that matches your JSON structure. In such cases, you can use JsonDocument for dynamic reading.

using System;
using System.IO;
using System.Text.Json;

class Program
{
    static void Main()
    {
        string filePath = "data.json";
        try
        {
            using FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            using JsonDocument doc = JsonDocument.Parse(fs);
            JsonElement root = doc.RootElement;

            string name = root.GetProperty("name").GetString();
            int age = root.GetProperty("age").GetInt32();
            bool isEmployed = root.GetProperty("isEmployed").GetBoolean();
            List<string> skills = new List<string>();

            Console.WriteLine($"Name: {name}");
            Console.WriteLine($"Age: {age}");
            Console.WriteLine($"Is Employed: {isEmployed}");
            Console.WriteLine("Skills: " + string.Join(", ", skills));
        }
        catch (Exception e)
        {
            Console.WriteLine($"An error occurred: {e.Message}");
        }
    }
}

Using JsonDocument allows you to navigate and read JSON data without needing a predefined data model. This method is useful when dealing with dynamic or unknown JSON structures.

Reading JSON files in C# using System.Text.Json is both straightforward and powerful. Whether you need to deserialize into a well-defined object, handle complex nested structures, or read dynamic data, System.Text.Json has you covered. As you work more with JSON in your applications, these techniques will become indispensable in your developer toolkit.

Read Large File using FileStream and BufferedStream

For reading very large files, you might need to use FileStream combined with BufferedStream. This approach minimizes memory usage by reading the file in small chunks.

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string filePath = "sample.txt";
        try
        {
            using FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            using BufferedStream bufferedStream = new BufferedStream(fileStream);
            using StreamReader reader = new StreamReader(bufferedStream);

            string fileContents = reader.ReadToEnd();
            Console.WriteLine(fileContents);
        }
        catch (IOException e)
        {
            Console.WriteLine($"An error occurred: {e.Message}");
        }
    }
}

FileStream provides a way to work directly with the file, while BufferedStream improves performance by reducing the number of I/O operations.

Read Binary File

If you need to read binary files, FileStream with BinaryReader is an appropriate approach.

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string filePath = "sample.bin";
        try
        {
            using FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            using BinaryReader reader = new BinaryReader(fileStream);

            byte[] fileContents = reader.ReadBytes((int)fileStream.Length);
            Console.WriteLine(BitConverter.ToString(fileContents));
        }
        catch (IOException e)
        {
            Console.WriteLine($"An error occurred: {e.Message}");
        }
    }
}

This method reads the file’s bytes, which is essential for binary data. BinaryReader is well-suited for reading primitive data types.

Error Handling

When dealing with file I/O, robust error handling is crucial. Always anticipate potential issues like file not found, access violations, or read/write errors.

try
{
    //
    // Perform File Reading Here
    //
}
catch (FileNotFoundException fnfe)
{
    Console.WriteLine($"File not found: {fnfe.Message}");
}
catch (UnauthorizedAccessException uae)
{
    Console.WriteLine($"Access denied: {uae.Message}");
}
catch (IOException ioe)
{
    Console.WriteLine($"I/O error: {ioe.Message}");
}

Implementing specific exceptions provides better diagnostics and user feedback.

Summary

Reading file contents into a variable in C# can be done in multiple ways, each is suited for different scenarios. Whether you are working with small text files or large binary data, understanding these methods allows you to choose the right tool for the job. Always consider the file size, performance implications, and the specific requirements of your application when selecting an approach.