Простые приложения на С++
December 26, 2024

Файловый менеджер на С++

Разработка файлового менеджера на C++ - это отличный способ углубить свои знания в области программирования, особенно в работе с файловой системой, обработке пользовательского ввода и создании графического интерфейса (если планируется GUI-версия). Файловый менеджер, по сути, является инструментом для навигации по файловой системе компьютера, позволяющим выполнять различные операции с файлами и директориями: создание, удаление, копирование, перемещение, переименование, просмотр свойств и т.д.

C++ предоставляет мощные средства для работы с файловой системой через стандартную библиотеку <filesystem> (начиная со стандарта C++17) и низкоуровневые API операционной системы (например, WinAPI для Windows или POSIX API для Linux/macOS). Выбор подхода зависит от требований к проекту:

- <filesystem> (C++17 и новее): Обеспечивает кроссплатформенность и более высокий уровень абстракции, что упрощает разработку и делает код более переносимым. Рекомендуется для большинства современных проектов.

- API операционной системы (WinAPI, POSIX): Предоставляет более полный контроль над файловой системой и доступ к специфическим функциям ОС, но делает код платформозависимым. Может потребоваться для задач, требующих максимальной производительности или доступа к низкоуровневым функциям.

В зависимости от того, какой интерфейс вы хотите реализовать, можно выделить два основных типа файловых менеджеров:

- консольные (CLI): Управление осуществляется через текстовые команды в командной строке или терминале. Проще в реализации, но менее удобны для пользователя.

- графические (GUI): Используют графический интерфейс пользователя (окна, кнопки, меню, списки файлов и т.д.). Более сложные в разработке, но обеспечивают интуитивно понятное управление.

В процессе разработки файлового менеджера на C++ вы столкнетесь с необходимостью решения следующих задач:

- получение списка файлов и директорий: Использование функций для чтения содержимого директорий.

- обработка путей к файлам: Работа с абсолютными и относительными путями, их нормализация и проверка корректности.

- операции с файлами и директориями: Реализация функций создания, удаления, копирования, перемещения и переименования файлов и директорий.

- обработка ошибок: Корректная обработка возможных ошибок при работе с файловой системой (например, отсутствие файла, недостаточно прав доступа и т.д.).

- пользовательский интерфейс (для GUI-версий): Создание и управление элементами графического интерфейса, обработка событий пользователя.

Далее мы рассмотрим пример простого консольного файлового менеджера написанного на С++20, используя модульность.

Если Вы используете VS2022 тогда создайте файл file_manager.ixx в других IDE возможно file_manager.cppm.

Этот файл содержит объявление интерфейса модуля file_manager. Здесь мы определяем класс FileManager и его методы.

export module file_manager;

export import <string>;
export import <vector>;
export import <filesystem>;

export class FileManager {
public:
// Конструктор, инициализирует файловый менеджер
    FileManager(); 
// Основной метод для отображения и взаимодействия с пользователем
    void display(); 
// Метод для создания файла
    void createFile(const std::string& filename); 
// Метод для удаления файла
    void deleteFile(const std::string& filename); 
// Метод для отображения списка файлов
    void listFiles(); 
// Метод для смены текущей директории
    void changeDirectory(const std::string& newDirectory); 
// Метод для смены текущего диска
    void changeDisk(); 
// Метод для отображения доступных логических дисков
    void listDisks(); 

private:
// Текущая директория
    std::string currentDirectory; 
// Список файлов в текущей директории
    std::vector<std::string> files; 
// Метод для обновления списка файлов
    void refresh(); 
// Метод для очистки консоли
    void clearConsole(); 
};

Файл file_manager.cpp реализует методы класса FileManager, а также используется для управления вводом/выводом и работы с файловой системой.

module;

#include <iostream>
#include <fstream>
#include <vector>
#include <stdexcept>
// Код, предназначенный для Windows
#ifdef _WIN32
#include <windows.h>
#endif

module file_manager;

namespace fs = std::filesystem;

// Константы для ANSI кодов цветов
const std::string RED = "\033[1;31m";
const std::string GREEN = "\033[1;32m";
const std::string YELLOW = "\033[1;33m";
const std::string RESET = "\033[0m";

// Конструктор класса FileManager, инициализирует текущий диск
FileManager::FileManager() {
// Отображаем доступные диски
    listDisks(); 
// Смена диска на указанный пользователем
    changeDisk(); 
}

// Метод для обновления списка файлов в текущей директории
void FileManager::refresh() {
    files.clear();
    for (const auto& entry : fs::directory_iterator(currentDirectory)) {
        files.push_back(entry.path().filename().string());
    }
}

// Метод для очистки консоли 
void FileManager::clearConsole() { 
// Код, предназначенный для Windows
#ifdef _WIN32 
    std::system("cls");
#else 
// Код, предназначенный для других операционных систем (например, Unix-подобных)
    std::system("clear"); 
#endif 
}

// Основной метод для отображения и взаимодействия с пользователем
void FileManager::display() {
    char choice;
    std::string filename;
    std::string newDirectory;
    std::string newDisk;

    while (true) {
        std::cout << "\nФайловый менеджер — Текущий каталог:" << currentDirectory << "\n";
        std::cout << "1. Список файлов\n";
        std::cout << "2. Создать файл\n";
        std::cout << "3. Удалить файл\n";
        std::cout << "4. Изменить каталог\n";
        std::cout << "5. Сменить диск\n";
        std::cout << "6. Очистить консоль\n";
        std::cout << "7. Выход\n";
        std::cout << "Введите свой выбор: ";
        std::cin >> choice;

        switch (choice) {
        case '1':
// Отображение списка файлов
            listFiles(); 
            break;
        case '2':
            std::cout << "Введите имя файла для создания: ";
            std::cin >> filename;
// Создание нового файла
            createFile(filename); 
            break;
        case '3':
            std::cout << "Введите имя файла для удаления: ";
            std::cin >> filename;
// Удаление указанного файла
            deleteFile(filename); 
            break;
        case '4':
            std::cout << "Введите новый каталог: ";
            std::cin >> newDirectory;
// Смена текущей директории
            changeDirectory(newDirectory); 
            break;
        case '5':
// Смена текущего диска
            changeDisk(); 
            break;
        case '6':
 // Очистить консоль
            clearConsole();
            break;
        case '7':
// Выход из программы
            return; 
        default:
            std::cout << RED << "Неверный выбор. Попробуйте еще раз." << RESET << "\n";
            break;
        }
    }
}

// Метод для создания нового файла
void FileManager::createFile(const std::string& filename) {
// Создаём новый файл
    std::ofstream outfile(currentDirectory + "/" + filename);
    outfile.close();
    refresh();
    std::cout << GREEN << "Файл успешно создан." << RESET << "\n";
}

// Метод для удаления файла
void FileManager::deleteFile(const std::string& filename) {
// Удаляем файл
    if (fs::remove(currentDirectory + "/" + filename)) {
        refresh();
        std::cout << GREEN << "Файл успешно удален." << RESET << "\n";
    }
    else {
        std::cout << RED << "Файл не найден." << RESET << "\n";
    }
}

// Метод для отображения списка файлов в текущей директории
void FileManager::listFiles() {
    std::cout << YELLOW << "\nФайлы в каталоге:\n" << RESET;
    for (const auto& file : files) {
        std::cout << YELLOW << "- " << file << RESET << "\n";
    }
}

// Метод для смены текущей директории
void FileManager::changeDirectory(const std::string& newDirectory) {
// Проверяем, существует ли указанный путь и является ли он директорией
    if (fs::exists(newDirectory) && fs::is_directory(newDirectory)) {
        currentDirectory = newDirectory;
        refresh();
        std::cout << GREEN << "Каталог изменен на " << currentDirectory << RESET << "\n";
    }
    else {
        std::cout << RED << "Неверный каталог. Попробуйте еще раз."<< RESET << "\n";
    }
}

// Метод для смены текущего диска
void FileManager::changeDisk() {
    std::string rootPath;
    do {
    std::cout << "Введите диск для далнейшей работы (например, C:\\ или /): ";
    std::string disk;
    std::cin >> disk;
    // Создаем строку для хранения пути к корневой директории диска
    rootPath = disk;
    // Проверяем, заканчивается ли строка символом '/' или '\\' 
    // Если нет, добавляем '/' в конец строки, чтобы путь был корректным
    if (disk.back() != '/' && disk.back() != '\\') {
        rootPath += "/";
    }
    // Проверяем, существует ли указанный путь и является ли он директорией
    if (fs::exists(rootPath) && fs::is_directory(rootPath)) {
    // Если путь корректен, обновляем текущую директорию
        currentDirectory = rootPath;
    // Обновляем список файлов в текущей директории
        refresh();
        std::cout << GREEN << "Диск изменен на " << disk << RESET << "\n";
    }
    else {
        std::cout << RED << "Неверный диск. Попробуйте еще раз." << RESET << "\n";
    }
    } while (!(fs::exists(rootPath) && fs::is_directory(rootPath)));
}

// Метод для отображения доступных логических дисков
void FileManager::listDisks() {
// Создаем вектор для хранения списка доступных логических дисков
    std::vector<std::string> disks;
#ifdef _WIN32
    
// Буфер для хранения имен дисков
    char buffer[256];
// Для Windows используем GetLogicalDriveStringsA для получения строки с именами логических дисков 
// Получаем строку с именами логических дисков
    DWORD result = GetLogicalDriveStringsA(sizeof(buffer) - 1, buffer);
// Проверяем, успешно ли выполнена операция и помещаем имена дисков в вектор
    if (result > 0 && result <= sizeof(buffer)) {
        char* drive = buffer;
// Перебираем все логические диски в буфере
        while (*drive) {
// Добавляем имя диска в вектор
            disks.push_back(drive);
// Переходим к следующему диску в строке
            drive += strlen(drive) + 1;
        }
    }
#else
// Для Unix-подобных систем добавляем корневой каталог в список дисков
    disks.push_back("/");
#endif
// Выводим список доступных логических дисков на экран
    std::cout << YELLOW << "Доступные диски:\n";
    for (const auto& disk : disks) {
        std::cout << "- " << disk << "\n";
    }
    std::cout << RESET;
}

Файл main.cpp содержит основную функцию программы, которая создает объект файлового менеджера и запускает его основной метод display.

#include <iostream>

import file_manager;

int main() {

    system("chcp 1251>nul");

    FileManager fm;
    
    fm.display();

    return 0;
}

Результат работы данной программы.

Телеграмм