1. Introduction
If static classes like File and Directory are like a Swiss Army knife: handy, quick to solve a problem, but not tied to a specific object, then FileInfo and DirectoryInfo are a personalized tool: created for a particular file or folder, they "know" a lot about it and let you work more conveniently and flexibly, especially when doing many operations on the same object.
Instance classes store details about a specific file system object, and after the first property load you don't necessarily need to hit the file system again for info (unless the object becomes stale).
- FileInfo — for working with a specific file.
- DirectoryInfo — for working with a specific directory (folder).
They contain properties and methods that let you get detailed info (size, creation date, extension, attributes available) and perform actions on the file/folder: copy, delete, move, etc.
How FileInfo and DirectoryInfo are structured
Both classes inherit from the common abstract class FileSystemInfo, which lets you write code that works with files and folders uniformly.
System.Object
|
System.MarshalByRefObject
|
System.IO.FileSystemInfo (abstract class)
| |
FileInfo DirectoryInfo
When to use instance classes?
- If you need a lot of info about one file/folder (size, last modified date, extension, attributes, etc.) and that data is used more than once.
- If you want to iterate all files/folders in a directory and work with each object as a "live" instance.
- For optimization, when it's important not to hit the file system unnecessarily (caching info).
- For more object-oriented code (backups, media library, file manager, etc.).
How to create a FileInfo or DirectoryInfo instance
using System.IO;
// Creating a FileInfo object for an existing (or non-existing!) file:
var fileInfo = new FileInfo("notes.txt");
// Creating a DirectoryInfo object for a folder:
var dirInfo = new DirectoryInfo(@"C:\Projects");
// You can use relative or absolute paths!
Important note: creating a FileInfo or DirectoryInfo object DOES NOT create the file/folder on the filesystem! It's just a description (a reference).
2. Working with FileInfo
Let's go through the main properties and methods of this class. Here's a cheat sheet:
| Property/method | What it returns | Usage example |
|---|---|---|
|
File name | |
|
Full path | |
|
File size in bytes | |
|
Parent directory (DirectoryInfo) | |
|
Does the file really exist? | |
|
File extension (.txt) | |
|
Creation date | |
|
Last modified date | |
|
Read-only? | |
| Methods | ||
|
Copy the file | |
|
Delete the file | |
|
Move the file | |
|
Open a read stream | |
|
Open a write stream | |
Example: File information
Let's add a small module that gets detailed info about a file using FileInfo.
Console.WriteLine("Enter the file name:");
string fileName = Console.ReadLine();
var file = new FileInfo(fileName);
if (file.Exists)
{
Console.WriteLine($"File name: {file.Name}");
Console.WriteLine($"Path: {file.FullName}");
Console.WriteLine($"Size: {file.Length} bytes");
Console.WriteLine($"Extension: {file.Extension}");
Console.WriteLine($"Creation date: {file.CreationTime}");
Console.WriteLine($"Last modified: {file.LastWriteTime}");
// Additionally: show parent directory
Console.WriteLine($"Parent folder: {file.DirectoryName}");
}
else
{
Console.WriteLine("File not found.");
}
Note: we don't read the file contents, we only get metadata.
Practice: Copying and deleting a file
// ... Inside main method after successfully printing file info:
Console.WriteLine("Enter the path for the file copy:");
string copyPath = Console.ReadLine();
try
{
file.CopyTo(copyPath);
Console.WriteLine($"File successfully copied to {copyPath}");
}
catch (IOException ex)
{
Console.WriteLine($"Failed to copy file: {ex.Message}");
}
// Now delete the copy
Console.WriteLine("Delete the file copy? (y/n):");
if (Console.ReadLine().Trim().ToLower() == "y")
{
var copyFile = new FileInfo(copyPath);
if (copyFile.Exists)
{
copyFile.Delete();
Console.WriteLine("Copy deleted.");
}
}
3. Working with DirectoryInfo
Let's see what DirectoryInfo offers:
| Property/method | What it returns | Usage example |
|---|---|---|
|
Folder name | |
|
Full path | |
|
Parent folder (DirectoryInfo) | |
|
Does the folder exist? | |
|
Creation date | |
|
Last modified date | |
| Methods | ||
|
Create the folder | |
|
Delete the folder | |
|
Array of files (array of FileInfo) | |
|
Array of subfolders (array of DirectoryInfo) | |
|
Enumerate files (returns IEnumerable<FileInfo>, deferred execution) | |
|
Move the folder | |
Example: Iterating files and folders
Console.WriteLine("Enter the folder path:");
string path = Console.ReadLine();
var dir = new DirectoryInfo(path);
if (!dir.Exists)
{
Console.WriteLine("Folder not found!");
return;
}
Console.WriteLine("\n--- Files ---");
foreach (var file in dir.GetFiles())
{
Console.WriteLine($"{file.Name} ({file.Length} bytes)");
}
Console.WriteLine("\n--- Subfolders ---");
foreach (var subDir in dir.GetDirectories())
{
Console.WriteLine(subDir.Name);
}
4. Useful nuances
Static methods vs instance classes
When to use which approach? If you're doing a quick one-off action — for example, File.Exists(path) or File.ReadAllText(path) — static methods shine. They're simpler and slightly faster thanks to minimal overhead.
If you want to get lots of info about a file or folder, perform repeated operations on that object, or just write OOP-style code — use instances of FileInfo and DirectoryInfo.
Interestingly, both approaches under the hood use similar low-level system calls. But instance classes cache some properties (size, date, attributes), minimizing file system calls — especially nice when iterating many files.
A bit about date and time handling
Properties CreationTime, LastWriteTime, LastAccessTime return values of type DateTime.
Console.WriteLine($"File created: {file.CreationTime:yyyy-MM-dd HH:mm:ss}");
Console.WriteLine($"Last modified: {file.LastWriteTime:yyyy-MM-dd HH:mm:ss}");
If a file or folder was changed on disk after you obtained the FileInfo or DirectoryInfo object, the cached info can become stale. To refresh it, call file.Refresh().
Tips and practical notes
- Instance classes are handy when you build a wrapper around the file system: backups, media library, indexer.
- They work great with LINQ: you can filter by size, date or extension and perform operations on selected objects.
- For bulk operations prefer EnumerateFiles() and EnumerateDirectories() over GetFiles()/GetDirectories() — lazy enumeration saves memory and speeds up startup.
Comparison of static and instance approaches
| Static methods | Instance classes | |
|---|---|---|
| Syntax | |
|
| Caching | No | Yes |
| Lots of info | You need to call many methods | It's on the object |
| OOP-style | No | Yes |
| Bulk operations | Inconvenient | Convenient |
| Stream work | Available | Available |
Refreshing info and objects
Objects FileInfo/DirectoryInfo cache values after first access to properties. If the object (file or folder) was changed on disk after creating the instance, to update info call the .Refresh() method.
var file = new FileInfo("notes.txt");
long oldSize = file.Length;
// Meanwhile someone (or you) changes the file outside the program
file.Refresh();
long newSize = file.Length;
This doesn't happen often, but if your program watches the file system — the mechanism matters.
5. Common mistakes when working with instance classes
Misconception: if you create an object new FileInfo("file.txt"), the file already exists. Actually, that's not true — the file appears only after an explicit write or calling Create().
Trying to get properties of a file that doesn't exist: some properties will return defaults (for example, size 0), but attempting to open a read stream will throw an exception.
Same applies to folders: creating DirectoryInfo doesn't guarantee the folder exists on disk until you call Create() or it actually appears.
GO TO FULL VERSION