Skip to content
This is my space, where experience meets the will to start over. This is my space, where experience meets the will to start over.

The first step is knowing where you want to go.

  • Home
  • Coding Hub
    • Software & Project
      • Small Biz Ops – S.B.O.
        • SmallBizOps – Day 10/90
      • CRM/ERP
      • MyTracker
      • My Budget
    • Form Zero to “WoW”
      • JavaScript from Zero (Completed)
        • 2. Remove and Edit List Items
        • 3. Separate HTML and JavaScript, Use addEventListener and Conditional Logic
        • 4. Add Dynamic CSS Classes
        • 5. Save & Restore Your List with localStorage
        • 6 – Turn Your App into a Full To-Do List
      • Python from Zero (Completed)
        • 2. Lists & Loops
        • 3. Conditional Menus
        • 4. Edit & Remove Tasks (with closing: Python vs PHP and Large Data)
        • 5 – Save to File: Make Your Tasks Survive Restarts
        • 6 — Pythin from zero – Final Project Polishing: Numbering, Formatting, and Preparing for CSV
      • Rust – From Zero to “WoW” (Completed)
        • 1 – Setup and Project Structure in Rust
        • 2 – User input: validation and error handling
        • 3 – Rust from Zero to “WoW – BMI Calculation and Conditional Logic
        • 4 –Rust – Clear, Formatted Output
        • 5 – Rust – Final Thoughts: Precision as a Form of Respect
      • Go from Zero to “WoW” (Completed)
        • 1 – Why Go Is Perfect for a Personal Expense Tracker
        • 2 – Logging Expenses and Console Input
        • 3 – Go from Zero to “WoW” – Smart Filtering & Display Logic
        • 4 – Go – Saving Data to Local Files
        • 5 – Go – Final Project – Expense Tracker in Go
      • C++ from Zero to “WoW” (Completed)
        • 1 – Why C++ for file organization?
        • 2 – C++ – File Type Detection and Classification
        • 3 – C++ – Creating & Managing Subfolders
        • 4 – C++ – Safe File Movement and User Feedback
        • 5 – C++ – Order as Mental Clarity
      • Ubuntu – From Zero to “WoW” (Completed)
        • 2 – Ubuntu – The Desktop Environment and Essential Commands
        • 3 – Ubuntu – Managing Files, Folders, and Permissions
        • 4 – Ubuntu – Installing and Updating Software with APT and Snap
        • 5 – Ubuntu – Customizing the Desktop Environment
        • 6 – Ubuntu – Network and Device Configuration
        • 7 – Ubuntu – User Management & System Security — “The Cathedral of Permissions”
        • 8 – Ubuntu – The Talking Machine: Terminal & Bash Scripting
        • 9 – Ubuntu – Ubuntu as a Server or Development Environment
        • 10 – Ubuntu – Backup, Maintenance & Troubleshooting
    • Git Hub Repository
      • Small Biz Ops – S.B.O.
      • Mini ERP – PHP & MySQL
      • CleverCRM (Java, Spring Boot)
      • FraudWatch (Python, FastAPI + scikit-learn)
      • OnboardIQ – Smart Onboarding Portal (Flask + SQLite Demo)
    • ArchPilot
      • 1-Users & Roles, End-to-End (Architecture, Database, and Cross-Framework Code)
      • 2 – Client Registry (CRM) Across Frameworks
      • 3 – Project & Budget Tracker (ERP)
      • 4 – Approval Workflow Engine Multi-step routing, status tracking, escalation paths
      • 5 – Audit Trail & Versioning
    • Small Biz Ops – S.B.O.
  • Vivere in USA
  • P4Y
  • Testi poetici
    • 1 – Sospeso
    • 2 – Il bicchiere di vetro quieto
    • 3 – Quando l’amore inciampa
    • 4 – Ma chi siete davvero?
    • 5 – Above the Thread of Day
    • 6 – The Truth That Doesn’t Exist
    • 7 – All of You, I Miss
    • 8 – The Captain and the Ocean
    • 9 – Between Light and Mist
    • 10 – Il peso delle scelte
  • Contact
  • Admin
This is my space, where experience meets the will to start over.
This is my space, where experience meets the will to start over.

The first step is knowing where you want to go.

Coding – Step 13.3 – C++ from Zero to “WoW” – Creating & Managing Subfolders

Posted on 7 Ottobre 20257 Ottobre 2025 By Francesco

Heads‑up: We focus on safe, repeatable file operations and production‑style error handling. The examples work on Windows, macOS, and Linux with a C++17‑capable compiler.


What You’ll Learn

By the end of this lesson, you’ll be able to:

  • Use std::filesystem to create single and nested directories.
  • Check existence, type (file vs directory), and permissions.
  • Implement idempotent create/remove logic with std::error_code (no exceptions path).
  • List and recursively traverse subfolders with filtering.
  • Provide a neat CLI with dry‑run and verbose output.

Project Structure

subfolders/
├─ src/
│  ├─ main.cpp            # CLI: parse args, call ops, print results
│  ├─ ops.hpp             # declarations for fs ops
│  └─ ops.cpp             # implementations using <filesystem>
├─ tests/
│  └─ smoke.cpp           # minimal smoke tests (no framework)
├─ CMakeLists.txt         # build config
└─ README.md

Minimal CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)
project(subfolders LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(subfolders src/main.cpp src/ops.cpp)

Core API Design (ops.hpp)

#pragma once
#include <filesystem>
#include <string>
#include <vector>

namespace sf {
  namespace fs = std::filesystem;

  struct CreateOpts {
    bool recursive = true;   // create nested folders
    bool dry_run   = false;  // print actions but don’t touch disk
    bool verbose   = true;   // log what happens
    fs::perms perms = fs::perms::owner_all | fs::perms::group_read | fs::perms::others_read;
  };

  struct RemoveOpts {
    bool recursive = true;
    bool dry_run   = false;
    bool verbose   = true;
  };

  // Returns true on success (idempotent). On error, returns false and sets ec.
  bool ensure_dir(const fs::path& p, const CreateOpts& opts, std::error_code& ec);

  // Returns number of removed entries. On error returns (size_t)-1 and sets ec.
  std::uintmax_t remove_dir(const fs::path& p, const RemoveOpts& opts, std::error_code& ec);

  // Lists immediate children matching an optional predicate.
  using PathList = std::vector<fs::path>;
  PathList list_children(const fs::path& p, bool include_files, bool include_dirs,
                         const std::string& name_contains, std::error_code& ec);

  // Recursively collects directories (depth‑first). If max_depth==0 => unlimited.
  PathList list_dirs_recursive(const fs::path& root, std::size_t max_depth,
                               const std::string& name_contains, std::error_code& ec);
}

Implementation (ops.cpp)

#include "ops.hpp"
#include <iostream>

namespace sf {
  namespace fs = std::filesystem;

  static void vlog(bool verbose, const std::string& msg){ if(verbose) std::cout << msg << '\n'; }

  bool ensure_dir(const fs::path& p, const CreateOpts& opts, std::error_code& ec) {
    ec.clear();
    if (opts.dry_run) { vlog(opts.verbose, "[dry-run] mkdir: " + p.string()); return true; }

    if (fs::exists(p, ec)) {
      if (ec) return false;
      if (fs::is_directory(p, ec)) { vlog(opts.verbose, "exists: " + p.string()); return !ec; }
      // A non-directory exists at path: error
      vlog(opts.verbose, "error: path exists but is not a directory: " + p.string());
      ec = std::make_error_code(std::errc::file_exists);
      return false;
    }

    bool ok = false;
    if (opts.recursive) ok = fs::create_directories(p, ec);
    else ok = fs::create_directory(p, ec);

    if (!ec) {
      // try to set permissions (best-effort; not all platforms honor this fully)
      std::error_code perm_ec;
      fs::permissions(p, opts.perms, perm_ec);
      vlog(opts.verbose, std::string("mkdir: ") + p.string());
      return true; // idempotent: treat existing as success
    }
    return false;
  }

  std::uintmax_t remove_dir(const fs::path& p, const RemoveOpts& opts, std::error_code& ec) {
    ec.clear();
    if (opts.dry_run) { vlog(opts.verbose, "[dry-run] rm" + std::string(opts.recursive?" -r":"") + ": " + p.string()); return 0; }

    if (!fs::exists(p, ec)) { return 0; }
    if (ec) return static_cast<std::uintmax_t>(-1);

    std::uintmax_t count = 0;
    if (opts.recursive) count = fs::remove_all(p, ec);
    else {
      bool ok = fs::remove(p, ec);
      count = ok ? 1 : 0;
    }

    if (!ec) vlog(opts.verbose, std::string("removed entries: ") + std::to_string(count));
    return ec ? static_cast<std::uintmax_t>(-1) : count;
  }

  sf::PathList list_children(const fs::path& p, bool include_files, bool include_dirs,
                             const std::string& name_contains, std::error_code& ec) {
    PathList out; ec.clear();
    if (!fs::exists(p, ec) || ec) return out;

    for (auto it = fs::directory_iterator(p, ec); !ec && it != fs::directory_iterator(); ++it) {
      const auto& entry = *it;
      bool is_file = entry.is_regular_file(ec);
      bool is_dir  = entry.is_directory(ec);
      const auto name = entry.path().filename().string();
      if (!name_contains.empty() && name.find(name_contains) == std::string::npos) continue;
      if ((include_files && is_file) || (include_dirs && is_dir)) out.push_back(entry.path());
    }
    return out;
  }

  sf::PathList list_dirs_recursive(const fs::path& root, std::size_t max_depth,
                                   const std::string& name_contains, std::error_code& ec) {
    PathList out; ec.clear();
    if (!fs::exists(root, ec) || ec) return out;

    std::size_t root_depth = std::distance(root.begin(), root.end());
    for (auto it = fs::recursive_directory_iterator(root, ec); !ec && it != fs::recursive_directory_iterator(); ++it) {
      const auto& entry = *it;
      if (!entry.is_directory(ec)) continue;
      auto path = entry.path();
      if (!name_contains.empty() && path.filename().string().find(name_contains) == std::string::npos) continue;
      std::size_t d = std::distance(path.begin(), path.end()) - root_depth;
      if (max_depth && d > max_depth) { it.disable_recursion_pending(); continue; }
      out.push_back(path);
    }
    return out;
  }
}

CLI Wiring (src/main.cpp)

#include "ops.hpp"
#include <iostream>
#include <string>

using namespace sf;

static void usage(){
  std::cout << "Usage:\n"
            << "  subfolders create <path> [--dry] [--no-rec] [--quiet]\n"
            << "  subfolders remove <path> [--dry] [--no-rec] [--quiet]\n"
            << "  subfolders ls <path> [--files] [--dirs] [--name <substr>]\n"
            << "  subfolders finddirs <root> [--max-depth N] [--name <substr>]\n";
}

int main(int argc, char** argv) {
  if (argc < 3) { usage(); return 1; }
  std::string cmd = argv[1];
  std::filesystem::path arg = argv[2];

  std::error_code ec;

  if (cmd == "create") {
    CreateOpts o{};
    for (int i=3; i<argc; ++i) {
      std::string f = argv[i];
      if (f=="--dry") o.dry_run=true; else if (f=="--no-rec") o.recursive=false; else if (f=="--quiet") o.verbose=false; }
    bool ok = ensure_dir(arg, o, ec);
    if (!ok || ec) { std::cerr << "create error: " << ec.message() << "\n"; return 2; }
  }
  else if (cmd == "remove") {
    RemoveOpts o{};
    for (int i=3; i<argc; ++i) { std::string f = argv[i]; if (f=="--dry") o.dry_run=true; else if (f=="--no-rec") o.recursive=false; else if (f=="--quiet") o.verbose=false; }
    auto n = remove_dir(arg, o, ec);
    if (n==(std::uintmax_t)-1 || ec) { std::cerr << "remove error: " << ec.message() << "\n"; return 3; }
  }
  else if (cmd == "ls") {
    bool inc_files=false, inc_dirs=true; std::string name;
    for (int i=3; i<argc; ++i) { std::string f = argv[i]; if (f=="--files") inc_files=true; else if (f=="--dirs") inc_dirs=true; else if (f=="--name" && i+1<argc) name=argv[++i]; }
    auto xs = list_children(arg, inc_files, inc_dirs, name, ec);
    if (ec) { std::cerr << "ls error: " << ec.message() << "\n"; return 4; }
    for (auto& p: xs) std::cout << p.string() << "\n";
  }
  else if (cmd == "finddirs") {
    std::size_t depth=0; std::string name;
    for (int i=3; i<argc; ++i) { std::string f = argv[i]; if (f=="--max-depth" && i+1<argc) depth=static_cast<std::size_t>(std::stoul(argv[++i])); else if (f=="--name" && i+1<argc) name=argv[++i]; }
    auto xs = list_dirs_recursive(arg, depth, name, ec);
    if (ec) { std::cerr << "finddirs error: " << ec.message() << "\n"; return 5; }
    for (auto& p: xs) std::cout << p.string() << "\n";
  }
  else {
    usage();
    return 1;
  }

  return 0;
}

Minimal Smoke Tests (tests/smoke.cpp)

#include "../src/ops.hpp"
#include <cassert>
#include <iostream>

int main(){
  using namespace sf;
  std::error_code ec;
  auto tmp = std::filesystem::temp_directory_path() / "sf_demo";

  // ensure
  CreateOpts c{}; c.verbose=false; c.dry_run=false; c.recursive=true;
  assert(ensure_dir(tmp/"a"/"b"/"c", c, ec));
  assert(!ec);

  // list children
  auto kids = list_children(tmp/"a"/"b", /*files*/false, /*dirs*/true, "", ec);
  assert(!ec && !kids.empty());

  // remove
  RemoveOpts r{}; r.verbose=false; r.recursive=true;
  auto n = remove_dir(tmp, r, ec);
  assert(!ec && n>0);

  std::cout << "OK\n";
}

Build & run (example):

cmake -S . -B build && cmake --build build
./build/subfolders create ./demo/a/b/c
./build/subfolders ls ./demo --dirs
./build/subfolders remove ./demo --no-rec   # fails if non‑empty (by design)
./build/subfolders remove ./demo            # recursive

Safety & Idempotency Notes

  • Use the error_code overloads to avoid exceptions in operational code.
  • Treat “already exists and is a directory” as success.
  • Fail if a non‑directory exists at the target path.
  • Log clearly in dry‑run mode to preview actions.

Nice‑to‑Haves

  • Add --mode 755 style permissions parsing on POSIX.
  • Add a --pattern glob (e.g., **/*.log) using a tiny matcher.
  • Add a copy_tree(src, dst) with collision strategies: skip/overwrite/rename.
  • Add colored output for actions and results.

Learning Checklist

  • I can create nested directories portably with <filesystem>.
  • I can check existence/type and handle collisions safely.
  • I can list and traverse subfolders (flat and recursive).
  • I can remove directories with and without recursion.
  • I can design a small, testable filesystem API.
Post Views: 194

Condividi:

  • Condividi su Facebook (Si apre in una nuova finestra) Facebook
  • Condividi su X (Si apre in una nuova finestra) X
Coding C++ c++CLIcross‑platformdirectorieserror handlingfilesystemidempotentpermissionssubfolders

Navigazione articoli

Previous post
Next post

Francesco

My name is Francesco Boschi, originally from Italy and currently based in the United States. For over twenty years, I’ve worked as a manager and consultant across diverse sectors — from education and cultural institutions to the food industry — developing skills in operational management, strategic consulting, and complex problem-solving. In recent years, I’ve combined this experience with a strong passion for software development, creating custom tools designed to simplify workflows and meet real business needs.

Relocating to the U.S. marks the beginning of a new chapter: a personal and professional decision driven by the desire to be close to my son and to embrace new challenges in a different environment. Today, my goal is to turn my experience into meaningful solutions, blending strategic vision with technical expertise to help people and organizations work more effectively.

I enjoy moving between different worlds, adapting tools and approaches to people and contexts. I bring leadership, flexibility, attention to detail, analytical thinking, and a strong problem-solving mindset — along with a deep curiosity to learn and grow. Above all, I believe in sharing: I’m always eager to offer my experience to support the growth of others.

Related Posts

Python

Coding – Step 10.5 – Python form Zero – Save to File: Make Your Tasks Survive Restarts

Posted on 23 Agosto 202523 Agosto 2025

We’ll add a simple persistence layer to our To-Do App by writing tasks into a .txt file and reloading them at startup. This ensures tasks don’t disappear between runs and sets the stage for JSON in Step 10.7.

Condividi:

  • Condividi su Facebook (Si apre in una nuova finestra) Facebook
  • Condividi su X (Si apre in una nuova finestra) X
Read More
Coding

Coding – Step 14.9 – Ubuntu – Ubuntu as a Server or Development Environment

Posted on 29 Ottobre 202529 Ottobre 2025

ransform Ubuntu into a personal development lab or private server. Learn how to host, code, and deploy safely — right from your own machine.

Condividi:

  • Condividi su Facebook (Si apre in una nuova finestra) Facebook
  • Condividi su X (Si apre in una nuova finestra) X
Read More
Coding

Coding – ArchPilot – Step 2 – Client Registry (CRM) Across Frameworks

Posted on 20 Novembre 202520 Novembre 2025

ArchPilot – Step 2 extends the multi-framework ERP/CRM showcase with a shared Client Registry module (organizations, contacts, interactions), implemented consistently across Laravel, Django, Spring Boot, ASP.NET Core, Node.js/Express, and Drupal, all wired into the RBAC and audit layer from Step 1.

Condividi:

  • Condividi su Facebook (Si apre in una nuova finestra) Facebook
  • Condividi su X (Si apre in una nuova finestra) X
Read More

Iscriviti alla nostra Newsletter

🤞 Let's keep in touch

We do not send spam! Read our Privacy policy for more information.

Controlla la tua casella di posta o la cartella spam per confermare la tua iscrizione

Cerca nel sito

©2026 This is my space, where experience meets the will to start over. | WordPress Theme by SuperbThemes