JS
C#

JavaScript to C#

10 lessons

Progress0%
1Variables & Types2Classes & OOP3Async/Await4Array Methods → LINQ5Exception Handling6Collections7Generics8Delegates and Events9Records and Pattern Matching10File I/O
All Mirror Courses
JS
C#
File I/O
MirrorLesson 10 of 10
Lesson 10

File I/O

Reading and writing files, JSON serialization, using statement

Introduction

In this lesson, you'll learn about file i/o in C#. Coming from JavaScript, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.

Mirror Card
JS
From JavaScript:

In JavaScript, you're familiar with reading and writing files, json serialization, using statement.

C#
In C#:

C# has its own approach to reading and writing files, json serialization, using statement, which we'll explore step by step.

The C# Way

Let's see how C# handles this concept. Here's a typical example:

C#
C# Example
using System.IO;
using System.Text.Json;

// Simple read/write (File class)
string text = File.ReadAllText("data.txt");
File.WriteAllText("out.txt", "Hello!");
File.AppendAllText("log.txt", "entry\n");

// Line-by-line (StreamReader)
using var reader = new StreamReader("data.txt");
while (!reader.EndOfStream)
{
    string? line = reader.ReadLine();
    Console.WriteLine(line);
}

// using ensures Dispose() is called — like JS finally{}
using var writer = new StreamWriter("out.txt");
writer.WriteLine("Hello!");

// JSON (System.Text.Json)
var obj = JsonSerializer.Deserialize<MyClass>(
    File.ReadAllText("data.json"));
File.WriteAllText("out.json",
    JsonSerializer.Serialize(obj, new JsonSerializerOptions
        { WriteIndented = true }));

// Path
string full = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data","file.txt");
Path.GetDirectoryName(full);
Path.GetExtension(full); // ".txt"

Comparing to JavaScript

Here's how you might have written similar code in JavaScript:

JS
JavaScript (What you know)
import fs from "fs";
import path from "path";

// Sync read/write
const text = fs.readFileSync("data.txt", "utf-8");
fs.writeFileSync("out.txt", "Hello!");
fs.appendFileSync("log.txt", "entry\n");

// Async (recommended)
const text2 = await fs.promises.readFile("data.txt","utf-8");
await fs.promises.writeFile("out.txt", "data");

// JSON
const obj = JSON.parse(fs.readFileSync("data.json","utf-8"));
fs.writeFileSync("out.json", JSON.stringify(obj, null, 2));

// Path
const full = path.join(__dirname, "data", "file.txt");
path.dirname(full);
path.extname(full); // ".txt"
Mirror Card
JS
From JavaScript:

You may be used to different syntax or behavior.

C#
In C#:

File.ReadAllText/WriteAllText are the simplest one-liner equivalents

Mirror Card
JS
From JavaScript:

You may be used to different syntax or behavior.

C#
In C#:

using statement calls Dispose() at end of block — equivalent to finally{stream.close()}

Mirror Card
JS
From JavaScript:

You may be used to different syntax or behavior.

C#
In C#:

StreamReader/StreamWriter for large files (streaming); File class for small files

Mirror Card
JS
From JavaScript:

You may be used to different syntax or behavior.

C#
In C#:

System.Text.Json is the built-in JSON library; Newtonsoft.Json is a popular alternative

Mirror Card
JS
From JavaScript:

You may be used to different syntax or behavior.

C#
In C#:

Path.Combine() replaces path.join() — handles OS path separators automatically

Step-by-Step Breakdown

1. File Class (Simple)

For small files, File.ReadAllText and File.WriteAllText are the simplest approach — synchronous and one-liner.

JS
JavaScript
fs.readFileSync("f","utf-8")
fs.writeFileSync("f","data")
C#
C#
File.ReadAllText("f")
File.WriteAllText("f","data")
File.ReadAllLines("f") // string[]

2. using Statement

The using statement automatically calls Dispose() when the block exits. StreamReader/Writer implement IDisposable.

JS
JavaScript
const f = fs.createReadStream("file");
try { ... } finally { f.close(); }
C#
C#
using var reader = new StreamReader("file");
// reader.Dispose() called automatically at }
Rule of Thumb
Always wrap streams in using — it prevents file handle leaks even on exceptions.

3. JSON Serialization

System.Text.Json is built into .NET. Use JsonSerializer.Deserialize<T> and Serialize. Add [JsonPropertyName] for custom field names.

JS
JavaScript
JSON.parse(text)
JSON.stringify(obj, null, 2)
C#
C#
var obj = JsonSerializer.Deserialize<Config>(text);
string json = JsonSerializer.Serialize(obj,
    new JsonSerializerOptions { WriteIndented = true });

4. Path Operations

Path.Combine handles OS-specific separators. Use Path.GetExtension, GetFileName, GetDirectoryName for path parts.

JS
JavaScript
path.join(dir, "sub", "file.txt")
path.extname("file.txt")
C#
C#
Path.Combine(dir, "sub", "file.txt")
Path.GetExtension("file.txt")  // ".txt"
Path.GetFileName("dir/file.txt") // "file.txt"

Common Mistakes

When coming from JavaScript, developers often make these mistakes:

  • File.ReadAllText/WriteAllText are the simplest one-liner equivalents
  • using statement calls Dispose() at end of block — equivalent to finally{stream.close()}
  • StreamReader/StreamWriter for large files (streaming); File class for small files
Common Pitfall
Don't assume C# works exactly like JavaScript. While the concepts may be similar, the syntax and behavior can differ significantly.

Key Takeaways

  • File.ReadAllText/WriteAllText for simple cases; StreamReader/Writer for large/streaming files
  • using statement auto-disposes streams — always use it with IO objects
  • System.Text.Json for JSON: Deserialize<T>() and Serialize() with JsonSerializerOptions
  • Path.Combine() for cross-platform paths; GetExtension/GetFileName for path parts
Rule of Thumb
The best way to learn is by doing. Try rewriting some of your JavaScript code in C# to practice these concepts.
PreviousFinish