Skip to main content
C# Fundamentals for Beginners to Advanced
CHAPTER 22 Beginner

File Handling in C#

Updated: May 17, 2026
5 min read

# CHAPTER 22

File Handling in C#

1. Introduction

When your C# program closes, all variables on the Stack and Heap are destroyed. If you want a user's high score or profile data to persist the next time they open the program, you must save it to the hard drive. File Handling via the System.IO namespace allows C# to read and write files permanently.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Use the System.IO namespace.
  • Use the static File class for quick reads/writes.
  • Use StreamWriter and StreamReader for handling large files.
  • Understand basic file paths.

3. The Static File Class (The Easy Way)

For small text files, the File class provides extremely simple one-liners to read and write data.
csharp
1234567891011121314151617181920
using System;
using System.IO; // CRITICAL: Required for file handling

class Program
{
    static void Main()
    {
        string filePath = "notes.txt";

        // 1. WRITE to a file (creates the file, or overwrites if it exists)
        File.WriteAllText(filePath, "Hello, this is my first saved file!");

        // 2. APPEND to a file (adds to the end without deleting existing content)
        File.AppendAllText(filePath, "\nHere is a second line.");

        // 3. READ from a file
        string content = File.ReadAllText(filePath);
        Console.WriteLine("File Content:\n" + content);
    }
}

4. Streams (StreamWriter / StreamReader)

If you are writing a massive log file (e.g., 500 MBs), using File.ReadAllText() will load the entire 500 MBs into your computer's RAM at once, potentially crashing the app.

Instead, we use Streams. Streams read/write data in small chunks (line by line).

csharp
123456789101112131415161718
using System.IO;

// Writing with StreamWriter
using (StreamWriter writer = new StreamWriter("log.txt", append: true))
{
    writer.WriteLine("User logged in at 10:00 AM");
} // The 'using' block automatically CLOSES and flushes the file when finished!

// Reading with StreamReader
using (StreamReader reader = new StreamReader("log.txt"))
{
    string line;
    // ReadLine() returns null when it reaches the End Of File (EOF)
    while ((line = reader.ReadLine()) != null)
    {
        Console.WriteLine(line);
    }
}

5. The using Statement (Memory Management)

Notice the using statement in the block above? (This is different from using System; at the top of the file).

When you open a file, the Operating System locks it. If your program crashes before you manually call writer.Close(), the file remains locked! Wrapping file operations in a using block guarantees that the file is safely closed and disposed of, even if an exception occurs.

6. File Paths

  • Relative Path: "notes.txt" saves the file exactly where the .exe is currently running from (usually bin/Debug/net8.0/).
  • Absolute Path: "C:\\Users\\Admin\\Desktop\\notes.txt" saves it to a specific hard drive location. Remember to use \\ or verbatim strings @"C:\..." to avoid escape character errors.

7. Checking if a File Exists

Before reading a file, you should always check if it exists to prevent a FileNotFoundException.
csharp
12345678
if (File.Exists("config.txt"))
{
    string config = File.ReadAllText("config.txt");
}
else
{
    Console.WriteLine("Configuration file missing!");
}

8. Mini Project: Notes Manager

csharp
1234567891011121314151617181920212223242526272829
using System;
using System.IO;

namespace NotesManager
{
    class Program
    {
        static void Main()
        {
            string path = "my_notes.txt";
            
            Console.WriteLine("Enter a note (Type EXIT to quit):");
            while (true)
            {
                string input = Console.ReadLine();
                if (input == "EXIT") break;
                
                File.AppendAllText(path, input + Environment.NewLine);
                Console.WriteLine("Note saved.");
            }

            Console.WriteLine("\n--- ALL NOTES ---");
            if (File.Exists(path))
            {
                Console.WriteLine(File.ReadAllText(path));
            }
        }
    }
}

9. Common Mistakes

  • File In Use Error: Trying to read a file while a StreamWriter still holds it open. Always close writers or use using blocks.
  • UnauthorizedAccessException: Trying to write a file to a protected system directory (like C:\Windows) without administrator privileges.

10. Best Practices

  • Always wrap StreamReader and StreamWriter in a using block.
  • Always check File.Exists() before attempting to read.

11. Exercises

  1. 1. Write a program that asks the user for their name and age, and writes it to a file called profile.txt.
  1. 2. Write a program that reads profile.txt and prints it to the console.

12. MCQs with Answers

Question 1

Which namespace is required for file handling in C#?

Question 2

Which static method reads an entire text file into a single string?

Question 3

Which static method adds text to the end of an existing file?

Question 4

Why should you use StreamReader instead of File.ReadAllText() for massive files?

Question 5

What does wrapping a StreamWriter in a using block do?

Question 6

How do you check if a file is actually on the hard drive before reading it?

Question 7

What happens if you run File.WriteAllText("data.txt", "Hello"); but "data.txt" already exists?

Question 8

What is the difference between a Relative Path and an Absolute Path?

Question 9

How do you safely write a Windows path with backslashes in C#?

Question 10

What property safely generates a newline character based on the current Operating System (Windows \r\n vs Linux \n)?

13. Interview Questions

  • Q: Explain the purpose of the using block in the context of IDisposable and file streams.
  • Q: Differentiate between File.WriteAllText() and StreamWriter.

14. Summary

The System.IO namespace gives your application persistence. For quick saves, the static File class is excellent. For large files or continuous logging, StreamWriter and StreamReader wrapped in using blocks guarantee safe, memory-efficient data streaming.

15. Next Chapter Recommendation

In Chapter 23: Delegates, Events, and Lambda Expressions, we will look at how to store methods inside variables and create systems where objects can trigger "Events" to notify other parts of your application.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·