C# Programming Tutorial 0/45 lessons ~6 min read Lesson 30

    File Handling

    File APIs span System.IO — File, Directory, FileStream, StreamReader/Writer, and async variants.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    File APIs span System.IO — File, Directory, FileStream, StreamReader/Writer, and async variants. Enterprise apps read configs, write audit logs, process CSV imports, and stream large exports without loading all into memory.

    Path.Combine avoids hardcoded separators. async File methods prevent thread blocking. Interviewers ask IDisposable with streams and secure path validation against directory traversal.

    The story

    A retail chain uploads nightly CSV inventory files from each store — SKU and quantity columns separated by commas. The import job reads the file line by line with a StreamReader so a 500 MB file never loads entirely into memory, skipping blank lines and malformed rows without crashing the batch.

    Understanding the topic

    Key concepts

    • File.ReadAllText quick but loads entire file.
    • FileStream for large sequential read/write.
    • StreamReader/Writer text encoding UTF-8 default.
    • Path.Combine, GetFullPath, GetExtension.
    • Directory.CreateDirectory, EnumerateFiles.
    • FileSystemWatcher monitors changes — use carefully.

    Step-by-step explanation

    1. Open stream → read/write chunks → flush → dispose.
    2. using var stream = File.OpenRead(path);
    3. await File.ReadAllTextAsync for async whole-file.
    4. EnumerateFiles with SearchOption.AllDirectories recursive.
    5. Locking: FileShare.Read for concurrent readers.
    6. Validate paths under allowed root — prevent ../ attacks.

    Practical code example

    Async line-by-line CSV import with StreamReader:

    csharp
    namespace TechLearningPro.Files;
    public static class CsvImporter
    {
    public static async Task<List<(string Sku, int Qty)>> ImportAsync(string path, CancellationToken ct)
    {
    if (!File.Exists(path)) throw new FileNotFoundException("CSV not found.", path);
    var rows = new List<(string, int)>();
    await using var stream = File.OpenRead(path);
    using var reader = new StreamReader(stream);
    while (await reader.ReadLineAsync(ct) is { } line)
    {
    if (string.IsNullOrWhiteSpace(line)) continue;
    var parts = line.Split(',', 2);
    if (parts.Length != 2 || !int.TryParse(parts[1], out var qty)) continue;
    rows.Add((parts[0].Trim(), qty));
    }
    return rows;
    }
    }

    Line-by-line code explanation

    • ImportAsync(string path, CancellationToken ct) is async so server threads are not blocked on disk I/O.
    • if (!File.Exists(path)) throw new FileNotFoundException(...) fails fast with a clear message when the file is missing.
    • await using var stream = File.OpenRead(path) opens a read stream with async disposal.
    • using var reader = new StreamReader(stream) wraps the byte stream with text decoding.
    • while (await reader.ReadLineAsync(ct) is { } line) reads lines until end-of-file, honoring cancellation.
    • if (string.IsNullOrWhiteSpace(line)) continue skips empty lines common in exported CSVs.
    • line.Split(',', 2) splits into at most two parts — SKU and quantity.
    • int.TryParse(parts[1], out var qty) safely parses quantity without throwing on bad data.
    • rows.Add((parts[0].Trim(), qty)) accumulates valid rows for downstream database insert.

    Key takeaway: StreamReader processes large files without loading all text. await using disposes async. Skip malformed lines or collect errors in production.

    Real-world use

    Where you'll use this in production

    • Nightly batch CSV ingestion to database.
    • Export audit trails to rolling log files.
    • Configuration files on disk in self-hosted apps.
    • Document upload storage to local filesystem.

    Best practices

    • Use async I/O for server file operations.
    • Always dispose streams — using/await using.
    • Validate paths stay within allowed directory.
    • Specify Encoding.UTF8 explicitly for cross-platform.
    • Use IFileProvider abstraction in ASP.NET Core apps.

    Common mistakes

    • ReadAllText on multi-GB files — OutOfMemoryException.
    • Forgetting Flush before close on writes.
    • Hardcoded backslashes — breaks on Linux.
    • No FileShare causing lock conflicts.

    Advanced interview questions

    Q1BeginnerFile vs FileStream?
    File static helpers; FileStream low-level stream control.
    Q2BeginnerWhy StreamReader?
    Text decoding layer over byte Stream.
    Q3IntermediateAsync file read pattern?
    await File.ReadAllTextAsync or ReadAsync on stream with buffer.
    Q4IntermediatePrevent path traversal?
    GetFullPath and verify starts with allowed root.
    Q5AdvancedProcess 10GB log file find errors.
    Stream line-by-line; optional parallel partition by offset; never ReadAllText.

    Summary

    Streams enable efficient large file processing. Async file APIs prevent thread pool blocking. Validate paths and encoding explicitly. Prefer abstraction IFileProvider in web apps. Next: serialization formats.

    Ready to mark this lesson complete?Track your journey across the entire course.