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

    Interview Prep

    Practice concise answers, then expand each card for the explanation.

    5 questions
    1BeginnerQuestionFile vs FileStream?+

    Answer

    File static helpers; FileStream low-level stream control.
    2BeginnerQuestionWhy StreamReader?+

    Answer

    Text decoding layer over byte Stream.
    3IntermediateQuestionAsync file read pattern?+

    Answer

    await File.ReadAllTextAsync or ReadAsync on stream with buffer.
    4IntermediateQuestionPrevent path traversal?+

    Answer

    GetFullPath and verify starts with allowed root.
    5AdvancedQuestionProcess 10GB log file find errors.+

    Answer

    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.