본문으로 건너뛰기 C++ File Operations | 'File Operations' Guide

C++ File Operations | 'File Operations' Guide

C++ File Operations | 'File Operations' Guide

이 글의 핵심

C++ File Operations: "File Operations" Guide. Basic file operations and directory operations.

Introduction

C++17 <filesystem> library provides standard API for file and directory manipulation. Replaces platform-specific APIs (POSIX, Windows API) to write portable code.


1. Basic File Operations

Basic Setup

#include <filesystem>
#include <iostream>

namespace fs = std::filesystem;

int main() {
    // Check file existence
    if (fs::exists("test.txt")) {
        std::cout << "File exists" << std::endl;
    }
    
    // File size
    auto size = fs::file_size("test.txt");
    std::cout << "Size: " << size << " bytes" << std::endl;
    
    return 0;
}

File Copy

// Basic copy
fs::copy_file("src.txt", "dst.txt");

// Overwrite
fs::copy_file("src.txt", "dst.txt", 
              fs::copy_options::overwrite_existing);

// Directory copy (recursive)
fs::copy("src_dir", "dst_dir", 
         fs::copy_options::recursive);

File Move and Delete

// Rename (move)
fs::rename("old.txt", "new.txt");

// Delete file
fs::remove("file.txt");

// Delete directory (recursive)
fs::remove_all("dir");

2. Directory Operations

Directory Creation

// Single directory
fs::create_directory("mydir");

// Nested directory (recursive)
fs::create_directories("path/to/dir");

// Returns false if already exists
bool created = fs::create_directory("existing_dir");
if (!created) {
    std::cout << "Already exists or creation failed" << std::endl;
}

Directory Traversal

#include <filesystem>
#include <iostream>

namespace fs = std::filesystem;

int main() {
    // Traverse current directory
    for (const auto& entry : fs::directory_iterator(".")) {
        std::cout << entry.path() << std::endl;
    }
    
    // Recursive traversal
    for (const auto& entry : fs::recursive_directory_iterator(".")) {
        if (entry.is_regular_file()) {
            std::cout << "File: " << entry.path() << std::endl;
        } else if (entry.is_directory()) {
            std::cout << "Directory: " << entry.path() << std::endl;
        }
    }
    
    return 0;
}

3. Copy Options

copy_options Flags

#include <filesystem>

namespace fs = std::filesystem;

// Default: error if already exists
fs::copy_file("src.txt", "dst.txt");

// Overwrite
fs::copy_file("src.txt", "dst.txt",
              fs::copy_options::overwrite_existing);

// Skip (ignore if exists)
fs::copy_file("src.txt", "dst.txt",
              fs::copy_options::skip_existing);

// Update (copy if newer)
fs::copy_file("src.txt", "dst.txt",
              fs::copy_options::update_existing);

// Recursive copy (directory)
fs::copy("src_dir", "dst_dir",
         fs::copy_options::recursive);

// Copy symbolic link (link itself)
fs::copy("link", "new_link",
         fs::copy_options::copy_symlinks);

copy_options Combination:

Here is a simple C++ code example. Try running the code directly to check its operation.

// Recursive + overwrite
fs::copy("src_dir", "dst_dir",
         fs::copy_options::recursive | 
         fs::copy_options::overwrite_existing);

4. Practical Examples

Example 1: Safe File Copy

#include <filesystem>
#include <iostream>

namespace fs = std::filesystem;

bool copyFileSafe(const fs::path& src, const fs::path& dst) {
    try {
        // Check source file exists
        if (!fs::exists(src)) {
            std::cerr << "Source file does not exist: " << src << std::endl;
            return false;
        }
        
        // Create destination directory
        fs::create_directories(dst.parent_path());
        
        // Copy file
        fs::copy_file(src, dst, 
                      fs::copy_options::overwrite_existing);
        
        std::cout << "Copy complete: " << src << " -> " << dst << std::endl;
        return true;
        
    } catch (const fs::filesystem_error& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return false;
    }
}

int main() {
    copyFileSafe("data/input.txt", "backup/input.txt");
    return 0;
}

Example 2: Directory Backup

Here is the backupDirectory implementation:

#include <filesystem>
#include <iostream>
#include <chrono>
#include <iomanip>
#include <sstream>

namespace fs = std::filesystem;

std::string getCurrentTimestamp() {
    auto now = std::chrono::system_clock::now();
    auto time = std::chrono::system_clock::to_time_t(now);
    
    std::stringstream ss;
    ss << std::put_time(std::localtime(&time), "%Y%m%d_%H%M%S");
    return ss.str();
}

void backupDirectory(const fs::path& src, const fs::path& backupRoot) {
    try {
        // Create backup directory with timestamp
        fs::path backupPath = backupRoot / (src.filename().string() + "_" + getCurrentTimestamp());
        
        // Recursive copy
        fs::copy(src, backupPath, 
                 fs::copy_options::recursive | 
                 fs::copy_options::overwrite_existing);
        
        std::cout << "Backup complete: " << backupPath << std::endl;
        
    } catch (const fs::filesystem_error& e) {
        std::cerr << "Backup failed: " << e.what() << std::endl;
    }
}

int main() {
    backupDirectory("project", "backups");
    // Result: backups/project_20260329_143025/
    return 0;
}

Example 3: Clean Old Files

#include <filesystem>
#include <iostream>
#include <chrono>

namespace fs = std::filesystem;

void cleanupOldFiles(const fs::path& dir, int days) {
    try {
        auto now = fs::file_time_type::clock::now();
        auto threshold = now - std::chrono::hours(24 * days);
        
        int deletedCount = 0;
        
        for (const auto& entry : fs::directory_iterator(dir)) {
            if (entry.is_regular_file()) {
                auto mtime = fs::last_write_time(entry);
                
                if (mtime < threshold) {
                    auto size = fs::file_size(entry);
                    fs::remove(entry.path());
                    
                    std::cout << "Deleted: " << entry.path() 
                              << " (" << size << " bytes)" << std::endl;
                    deletedCount++;
                }
            }
        }
        
        std::cout << "Total " << deletedCount << " files deleted" << std::endl;
        
    } catch (const fs::filesystem_error& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
}

int main() {
    cleanupOldFiles("temp", 7);  // Delete files older than 7 days
    return 0;
}

Example 4: File Synchronization

#include <filesystem>
#include <iostream>

namespace fs = std::filesystem;

void syncDirectories(const fs::path& src, const fs::path& dst) {
    try {
        for (const auto& entry : fs::recursive_directory_iterator(src)) {
            auto relativePath = fs::relative(entry.path(), src);
            auto dstPath = dst / relativePath;
            
            if (entry.is_directory()) {
                // Create directory
                fs::create_directories(dstPath);
            } else if (entry.is_regular_file()) {
                // Copy if doesn't exist or is newer
                if (!fs::exists(dstPath) || 
                    fs::last_write_time(entry) > fs::last_write_time(dstPath)) {
                    
                    fs::copy_file(entry.path(), dstPath,
                                  fs::copy_options::overwrite_existing);
                    std::cout << "Synced: " << relativePath << std::endl;
                }
            }
        }
        
    } catch (const fs::filesystem_error& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
}

int main() {
    syncDirectories("source", "destination");
    return 0;
}

5. Common Issues

Issue 1: Overwrite Error

#include <filesystem>
#include <iostream>

namespace fs = std::filesystem;

int main() {
    // ❌ Error if already exists
    try {
        fs::copy_file("src.txt", "existing.txt");
    } catch (const fs::filesystem_error& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        // filesystem error: cannot copy file: File exists
    }
    
    // ✅ Specify option
    fs::copy_file("src.txt", "existing.txt",
                  fs::copy_options::overwrite_existing);
    
    return 0;
}

Solution: Explicitly specify copy_options.

Issue 2: Directory Delete Failure

// ❌ Non-empty directory
try {
    fs::remove("non_empty_dir");  // Fails!
} catch (const fs::filesystem_error& e) {
    std::cerr << e.what() << std::endl;
    // Directory not empty
}

// ✅ Recursive delete
int removed = fs::remove_all("non_empty_dir");
std::cout << removed << " items deleted" << std::endl;

Solution: Use remove_all() for non-empty directories.

Issue 3: Move vs Copy

// Move (fast, atomic)
try {
    fs::rename("old.txt", "new.txt");
    // Only works within same filesystem
} catch (const fs::filesystem_error& e) {
    // Fails if different filesystem
    std::cerr << "Move failed: " << e.what() << std::endl;
}

// Copy + delete (slow, non-atomic)
fs::copy_file("src.txt", "dst.txt");
fs::remove("src.txt");
// Both files may exist if fails in middle

Solution: Use rename() within same filesystem, copy() + remove() across filesystems.


Master C++17 file operations! 🚀


Frequently Asked Questions (FAQ)

Q. When would I use this in practice?

A. Everything about C++ File Operations : from basic concepts to practical applications.

Q. What should I read before this?

A. Follow the previous article or related articles links at the bottom of each post to learn in sequence. See the C++ series index for the full picture.

Q. Where can I study this more deeply?

A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.


Other articles related to this topic.


Keywords Covered in This Article (Related Search Terms)

This article covers C++, file-operations, filesystem, C++17, copy.