I first started with Python and that worked well.  I then did a perl version.   That went well.   So, I thought – why not go for the jugular – write a c++ one.  I call it file_audit – save a csv formatted file so I can review and sort by date to see what I need to save or delete.  This code requires “.pdf” not “pdf” for the extension.

Here is my prompt

write a c++ program that take argv of --dir for directory, --csvfile for output csv file and type for extension file type such as .pdf or txt.   write the output to a the specified csv file, the csv file should contane file name, direcotry, size and date in format YYYY/MM/DD and time

Here is what it generated

// Include the necessary libraries
#include <iostream>
#include <string>
#include <filesystem>
#include <fstream>
#include <chrono>
#include <iomanip>

// Use the std namespace
using namespace std;

// Define a function to parse the command line arguments and return the values
void parse_args(int argc, char* argv[], string& dir, string& csvfile, string& type) {
    // Loop through the arguments
    for (int i = 1; i < argc; i++) {
        // Check if the argument is --dir
        if (string(argv[i]) == "--dir") {
            // Check if the next argument exists and is not another option
            if (i + 1 < argc && argv[i + 1][0] != '-') {
                // Assign the next argument to dir
                dir = argv[i + 1];
                // Increment i to skip the next argument
                i++;
            }
            else {
                // Throw an exception if the argument is invalid
                throw invalid_argument("Missing or invalid value for --dir");
            }
        }
        // Check if the argument is --csvfile
        else if (string(argv[i]) == "--csvfile") {
            // Check if the next argument exists and is not another option
            if (i + 1 < argc && argv[i + 1][0] != '-') {
                // Assign the next argument to csvfile
                csvfile = argv[i + 1];
                // Increment i to skip the next argument
                i++;
            }
            else {
                // Throw an exception if the argument is invalid
                throw invalid_argument("Missing or invalid value for --csvfile");
            }
        }
        // Check if the argument is --type
        else if (string(argv[i]) == "--type") {
            // Check if the next argument exists and is not another option
            if (i + 1 < argc && argv[i + 1][0] != '-') {
                // Assign the next argument to type
                type = argv[i + 1];
                // Increment i to skip the next argument
                i++;
            }
            else {
                // Throw an exception if the argument is invalid
                throw invalid_argument("Missing or invalid value for --type");
            }
        }
        else {
            // Throw an exception if the argument is unknown
            throw invalid_argument("Unknown option: " + string(argv[i]));
        }
    }
}

// Define a function to format a file time point as YYYY/MM/DD HH:MM:SS
string format_time(filesystem::file_time_type file_time) {
    // Convert the file time point to system clock time point
    auto sys_time = chrono::time_point_cast<chrono::system_clock::duration>(file_time - filesystem::file_time_type::clock::now() + chrono::system_clock::now());
    // Convert the system clock time point to time_t
    time_t tt = chrono::system_clock::to_time_t(sys_time);
    // Convert the time_t to tm structure
    tm local_tm = *localtime(&tt);
    // Create a string stream to format the output
    stringstream ss;
    // Write the year, month, day, hour, minute and second to the stream with leading zeros and separators
    ss << setw(4) << setfill('0') << local_tm.tm_year + 1900 << "/";
    ss << setw(2) << setfill('0') << local_tm.tm_mon + 1 << "/";
    ss << setw(2) << setfill('0') << local_tm.tm_mday << " ";
    ss << setw(2) << setfill('0') << local_tm.tm_hour << ":";
    ss << setw(2) << setfill('0') << local_tm.tm_min << ":";
    ss << setw(2) << setfill('0') << local_tm.tm_sec;
    // Return the formatted string
    return ss.str();
}

// Define a function to write the output to a csv file
void write_csv(const string& dir, const string& csvfile, const string& type) {
    // Create an output file stream and open the csv file
    ofstream ofs;
    ofs.open(csvfile);
    // Check if the file stream is open and ready
    if (ofs.is_open()) {
        // Write the header row to the csv file
        ofs << "File Name,Directory,Size,Date\n";
        // Loop through the directory entries in the given directory recursively
        for (const auto& entry : filesystem::recursive_directory_iterator(dir)) {
            // Check if the entry is a regular file and has the given extension type
            if (entry.is_regular_file() && entry.path().extension() == type) {
                // Write the file name, directory, size and date to the csv file with commas as separators and quotes as delimiters
                ofs << "\"" << entry.path().filename().string() << "\",";
                ofs << "\"" << entry.path().parent_path().string() << "\",";
                ofs << "\"" << entry.file_size() << "\",";
                ofs << "\"" << format_time(entry.last_write_time()) << "\"\n";
            }
        }
        // Close the file stream
        ofs.close();
    }
    else {
        // Throw an exception if the file stream is not open or ready
        throw runtime_error("Failed to open or write to " + csvfile);
    }
}

// Define the main function
int main(int argc, char* argv[]) {
    try {
        // Declare variables for directory, csv file and type arguments
        string dir, csvfile, type;
        // Parse the command line arguments and assign values to variables
        parse_args(argc, argv, dir, csvfile, type);
        // Write the output to a csv file with given arguments
        write_csv(dir, csvfile, type);
        // Print a success message to standard output
        cout << "Output written to " << csvfile << "\n";
    }
    catch (const exception& e) {
        // Print an error message to standard error with exception message
        cerr << "Error: " << e.what() << "\n";
        return 1;
    }
}

cool and it compiles.

I asked it to add a “-h” for help and got this.   I ended up just pasting in the changed section.

// Define a function to parse the command line arguments and return the values
void parse_args(int argc, char* argv[], string& dir, string& csvfile, string& type) {
    // Loop through the arguments
    for (int i = 1; i < argc; i++) {
        // Check if the argument is -h
        if (string(argv[i]) == "-h") {
            // Print the usage message and exit
            cout << "Usage: " << argv[0] << " --dir <directory> --csvfile <csv file> --type <file type>\n";
            cout << "Options:\n";
            cout << "  --dir <directory>   Specify the directory to scan recursively\n";
            cout << "  --csvfile <csv file> Specify the output csv file name\n";
            cout << "  --type <file type>   Specify the file extension type to filter\n";
            cout << "  -h                   Show this help message and exit\n";
            exit(0);
        }
        // Check if the argument is --dir
        else if (string(argv[i]) == "--dir") {
            // Check if the next argument exists and is not another option
            if (i + 1 < argc && argv[i + 1][0] != '-') {
                // Assign the next argument to dir
                dir = argv[i + 1];
                // Increment i to skip the next argument
                i++;
            }
            else {
                // Throw an exception if the argument is invalid
                throw invalid_argument("Missing or invalid value for --dir");
            }
        }
        // Check if the argument is --csvfile
        else if (string(argv[i]) == "--csvfile") {
            // Check if the next argument exists and is not another option
            if (i + 1 < argc && argv[i + 1][0] != '-') {
                // Assign the next argument to csvfile
                csvfile = argv[i + 1];
                // Increment i to skip the next argument
                i++;
            }
            else {
                // Throw an exception if the argument is invalid
                throw invalid_argument("Missing or invalid value for --csvfile");
            }
        }
        // Check if the argument is --type
        else if (string(argv[i]) == "--type") {
            // Check if the next argument exists and is not another option
            if (i + 1 < argc && argv[i + 1][0] != '-') {
                // Assign the next argument to type
                type = argv[i + 1];
                // Increment i to skip the next argument
                i++;
            }
            else {
                // Throw an exception if the argument is invalid
                throw invalid_argument("Missing or invalid value for --type");
            }
        }
        else {
            // Throw an exception if the argument is unknown
            throw invalid_argument("Unknown option: " + string(argv[i]));
        }
    }
}

For FreeBSD 12.4 – I had to use gcc12 to compile it.

for LLVM – c++

 

c++ -std=gnu++2a file_audit.cpp -o file_audit_2

Here is a typical run

 

./file_audit –dir $HOME –type .py –csvfile test2.csv

[jon2allen@freebsd12_4 ~/c++]$ head test2.csv
File Name,Directory,Size,Date
"daily_weather_obs_chart.py","/home/jon2allen/github/weather_obs","11008","2023/01/24 10:43:09"
"date_from_obs.py","/home/jon2allen/github/weather_obs","1540","2023/01/24 10:43:09"
"email_obs_err.py","/home/jon2allen/github/weather_obs","1078","2023/01/24 10:43:09"
"get_noaa_sites.py","/home/jon2allen/github/weather_obs","5233","2023/01/24 10:43:09"
"get_station_latest.py","/home/jon2allen/github/weather_obs","2234","2023/01/24 10:43:09"
"lambda_handler.py","/home/jon2allen/github/weather_obs","718","2023/01/24 10:43:09"
"noaa_duplicates.py","/home/jon2allen/github/weather_obs","1655","2023/01/24 10:43:09"
"noaa_tidal_potomac.py","/home/jon2allen/github/weather_obs","6490","2023/01/24 10:43:09"
"noaa_tide_chart_puller.py","/home/jon2allen/github/weather_obs","12372","2023/01/24 10:43:09"

 

 

 

 

 

Leave a Reply