1. Copying files
So far our filesystem operations were kind of "single strike": create a file, read it, delete it — done. But in the real world you often need to copy content: backups, duplicating templates, automating data workflows. Copying sounds trivial (Ctrl+C and Ctrl+V for the win), but there are plenty of nuances.
Today we'll go over all ways to copy files and folders — from the simplest to slightly more advanced. We'll also see how built-in .NET classes handle this, what limitations exist, what errors can trip you up and what to do if you suddenly have two thousand directories and a million files.
Class File and method Copy
The simplest way to copy a file is to use the static method File.Copy. This method takes the source file path, the destination file path and an optional parameter: whether to allow overwriting if the file already exists.
using System.IO;
// Simple example of copying a file
File.Copy("source.txt", "destination.txt");
If the destination file already exists, the method will throw an exception. To explicitly allow overwriting, use the third parameter:
File.Copy("source.txt", "destination.txt", overwrite: true);
Important note: If the second parameter ("destination.txt") is the path to an existing directory rather than a file, you'll get an error. The method expects a path to a file!
Working with paths
As before, don't forget to use Path.Combine so you don't fall into traps with doubled or backslashes:
string sourcePath = Path.Combine("Data", "input.txt");
string destPath = Path.Combine("Backup", "input_backup.txt");
File.Copy(sourcePath, destPath, overwrite: true);
Error handling
What can go wrong when copying a file? Lots: the file might be locked by another process, the source file might be missing, you might lack permissions, the destination disk might be full. Use exception handling:
try
{
File.Copy("bigdata.txt", "bigdata_backup.txt", overwrite: false);
Console.WriteLine("File copied successfully!");
}
catch (IOException ex)
{
Console.WriteLine($"I/O error: {ex.Message}");
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("No access to the file or folder.");
}
catch (Exception ex)
{
Console.WriteLine($"Other error: {ex.Message}");
}
Class FileInfo and method CopyTo
If you already have a FileInfo object, you can call CopyTo on it:
var fi = new FileInfo("report.xlsx");
fi.CopyTo("backup_report.xlsx");
The third argument (overwrite) in CopyTo appeared only in .NET Core 2.0+, so if you're targeting an older framework version — don't be surprised by an error.
Copying a file "into nowhere" (or "not caught — not stolen")
Pay attention to the destination path when copying. If the destination folder doesn't exist, .NET will throw. So before copying a file it's a good idea to ensure the target directory exists:
string backupDir = "Backup";
if (!Directory.Exists(backupDir))
{
Directory.CreateDirectory(backupDir);
}
string targetPath = Path.Combine(backupDir, "mydoc.txt");
File.Copy("mydoc.txt", targetPath);
2. Copying directories: not for the faint-hearted
This is where the real adventures begin! .NET doesn't provide a magical Directory.Copy that does it all in one line (like File). You'll have to do some manual work and write a function to recursively copy all files and subfolders.
Why isn't there a Directory.Copy?
Directory copying isn't always trivial. Each folder can contain files, subfolders, hidden files, files with special permissions and long paths. So the .NET folks decided: "Let programmers decide what to copy." But we don't take the easy route — we'll write our own function!
Example of recursive directory copying
Task: copy the contents of one folder (and all its sub-universe) into another.
using System;
using System.IO;
void CopyDirectory(string sourceDir, string destDir, bool recursive)
{
// Check if the source folder exists
if (!Directory.Exists(sourceDir))
throw new DirectoryNotFoundException($"Source folder not found: {sourceDir}");
// Create destination folder if it doesn't exist yet
if (!Directory.Exists(destDir))
Directory.CreateDirectory(destDir);
// Copy all files
foreach (string filePath in Directory.GetFiles(sourceDir))
{
string fileName = Path.GetFileName(filePath);
string destFilePath = Path.Combine(destDir, fileName);
File.Copy(filePath, destFilePath, overwrite: true);
}
// If recursive — copy all subfolders
if (recursive)
{
foreach (string dirPath in Directory.GetDirectories(sourceDir))
{
string dirName = Path.GetFileName(dirPath);
string destSubDir = Path.Combine(destDir, dirName);
// Recursive call!
CopyDirectory(dirPath, destSubDir, recursive);
}
}
}
Usage:
CopyDirectory("C:\\MyData", "D:\\Backup\\MyData", recursive: true);
This function creates the directory structure and copies all files, including the contents of subfolders.
We analyze the code and nuances
We first create the destination directory (if it doesn't exist) — otherwise trying to copy files there will fail. Inside each loop we use Path.GetFileName so we don't lose the file or folder name when building the new path.
By the way, if you copy a directory into itself or into its subfolder you'll get epic recursion… and a StackOverflowException. Don't copy "C:\\Data" into "C:\\Data\\Backup". The computer will be upset!
Copying files only (no subfolders)
Sometimes it's enough to copy only top-level files (without descending into subfolders):
void CopyFilesOnly(string sourceDir, string destDir)
{
if (!Directory.Exists(destDir))
Directory.CreateDirectory(destDir);
foreach (string filePath in Directory.GetFiles(sourceDir))
{
string fileName = Path.GetFileName(filePath);
string destFilePath = Path.Combine(destDir, fileName);
File.Copy(filePath, destFilePath, overwrite: true);
}
}
Example — implement backup
Let's add this functionality to our "HomeApp" that we've been building through the course. Let it now be able to make a backup of its data.
using System;
using System.IO;
namespace HomeApp
{
class Program
{
static void CopyDirectory(string sourceDir, string destDir, bool recursive)
{
if (!Directory.Exists(sourceDir))
throw new DirectoryNotFoundException($"Source folder not found: {sourceDir}");
if (!Directory.Exists(destDir))
Directory.CreateDirectory(destDir);
foreach (string filePath in Directory.GetFiles(sourceDir))
{
string fileName = Path.GetFileName(filePath);
string destFilePath = Path.Combine(destDir, fileName);
File.Copy(filePath, destFilePath, overwrite: true);
}
if (recursive)
{
foreach (string dirPath in Directory.GetDirectories(sourceDir))
{
string dirName = Path.GetFileName(dirPath);
string destSubDir = Path.Combine(destDir, dirName);
CopyDirectory(dirPath, destSubDir, recursive);
}
}
}
static void Main(string[] args)
{
Console.WriteLine("Enter the path to the working directory:");
string source = Console.ReadLine()!;
Console.WriteLine("Enter the path to the backup folder:");
string dest = Console.ReadLine()!;
try
{
CopyDirectory(source, dest, recursive: true);
Console.WriteLine("Backup created successfully!");
}
catch (Exception ex)
{
Console.WriteLine("Error while copying: " + ex.Message);
}
}
}
}
3. Useful nuances
Comparison: file vs directory — table
| File | Directory | |
|---|---|---|
| Built-in method | |
- |
| Object-oriented | |
- |
| Traversal of nesting | Not required | Requires recursion |
| Creating structure | Automatic | Need to create nesting manually |
| Risk of recursion | No | Yes — don't copy "into itself" |
Practical use and exercises
Copying files and folders is everywhere: from backups to data migration or updating resources in game launchers. These procedures are usually automated so you don't end up doing manual work and saying "oh, I forgot a file!" on Monday morning.
Directory copying is required in scenarios where you need to preserve not only content but the "skeleton" of the structure, including subfolders, nested files and settings.
Checklist for copying (so you don't mess up)
- Source exists
- Destination folder exists (create when needed via Directory.CreateDirectory)
- Overwrite scenario — do you need overwrite: true?
- Are you copying the folder "into itself"?
- Are you exceeding path length limits (especially on Windows)?
- Do you account for hidden/system files?
4. Special cases and common copying errors
Permissions
Copying can fail if your program doesn't have read permissions for source files or write permissions to the destination directory. In that case you'll get an UnauthorizedAccessException. The fix — run the program as administrator (only if it's really necessary!) or choose normal folders for copying.
Locked files
If a file is open in another program (for example, Excel locks it), File.Copy may throw. Make sure the application locking the file doesn't interfere, or implement retry logic (try-catch with retries).
Overwriting files
Which logic to choose: overwrite destination files or leave them alone? For backups it's usually fine to overwrite (overwrite: true), while for duplicating templates you may not want to (overwrite: false).
Copying hidden and system files
By default the methods we used (Directory.GetFiles) return all files, including hidden and system. If you need to skip them, filter explicitly:
foreach (string filePath in Directory.GetFiles(sourceDir))
{
var attr = File.GetAttributes(filePath);
if ((attr & FileAttributes.Hidden) == FileAttributes.Hidden)
continue; // Skip hidden files
// Rest of copy code
}
Long path errors
Windows long limited paths to about 260 characters for a long time. In modern versions this can be lifted, but if you're working on old systems long paths may be a problem.
Symbolic links and junctions
In specific scenarios directories may contain symbolic links or junctions. Normal copy methods may copy them as regular folders or ignore them. For most learning tasks this doesn't matter, but if you work with system directories — be careful.
GO TO FULL VERSION