ulfben icon

FilteredDeleter

ulfben | PRO | 01/02/18 10:31:43 PM UTC | 0 ⭐ | 1225 👁️ | Never ⏰ | []
C++ |

3.62 KB

|

None

|

0 👍

/

0 👎

// FilteredDeleter deletes all files in the target folder, which does not exist in the source folder. 
// It only looks at file names and ignores file extension. 
 
// It solves a niche problem for me, after photographing big events. 
// I shoot JPG+RAW. RAW files are enormously slow to flip through. 
// Thus, when I manually cull the set - throwing out all unusable photos - 
// -I only look at the JPGs. Leaving me with:
//    -a (source) folder of curated (JPG) files (<1000s of files, <10GB)</li>
//    -a (target) folder with *all* (RAW) files (>1000s of files, >50GB)</li>
// This program deletes all the unneeded RAW files.
// TODO: implement the command line interface
#include <algorithm>
#include <filesystem>
#include <cctype>
#include <iterator>
#include <iostream>
#include <string>
#include "ProgramOptions.h"
using namespace std::string_literals;
namespace fs = std::experimental::filesystem;
using PathList = std::vector<fs::path>;
PathList getFileList(const fs::path& dir); //returns a sorted list of file paths
PathList getDifference(const PathList& source, const PathList& target);
bool userConfirm(const std::string& message, const std::string& yes = "y"s);
void deleteFiles(const PathList& toRemove);
template<typename C, typename T = fs::path> void printEach(const C& v);
 
int main(int argc, char* argv[]){
    const ProgramOptions opts(argc, argv);      
    const auto source = fs::path{R"(Y:\Temp\WeddingPhotosChosen)"}; //Q&D: hardcoding paths...
    const auto target = fs::path{R"(Y:\Temp\WeddingPhotosRAW)"}; //TODO: use the ProgramOptions command line interface
    const PathList sourceFiles = getFileList(source);
    const PathList targetFiles = getFileList(target);
    const PathList toRemove = getDifference(sourceFiles, targetFiles);  
    printEach(toRemove);        
    if(userConfirm("Press Y to delete these files."s)){
        deleteFiles(toRemove);
    }
    userConfirm("Done! Double-check the error output\n\tbefore you press any key to quit."s);
    return 0;
}
 
PathList getDifference(const PathList& sourceFiles, const PathList& targetFiles){
    //Copies the elements from the sorted range [targets) 
    //which are not found in the sorted range [source) 
    //to the list toRemove.
    PathList toRemove;
    std::set_difference(targetFiles.begin(), targetFiles.end(),
        sourceFiles.begin(), sourceFiles.end(),
        std::inserter(toRemove, toRemove.begin()),
        [](const fs::path& source, const fs::path& target){
            return source.stem() < target.stem(); //comparing only filenames
        }
    );
    return toRemove;
}
template<typename C, typename T>
void printEach(const C& v){
    std::copy(std::begin(v), std::end(v), std::ostream_iterator<T>{std::cout, ",\n"});
    std::cout << '\n';
}
PathList getFileList(const fs::path& dir){
    PathList out;
    if(!fs::exists(dir) || !fs::is_directory(dir)){
        return out;
    }
    for(const auto& entry : fs::directory_iterator(dir)){
        if(fs::is_regular_file(entry.status())){
            out.push_back(entry.path());
        }
    }
    std::sort(out.begin(), out.end());
    return out;
}
void deleteFiles(const PathList& toRemove){
    for(const auto& file : toRemove){
        if(!is_regular_file(file)){
            std::cerr << "Warning: skipping non-file: "s << file.filename().string();
            continue;
        }
        if(!fs::remove(file)){
            std::cerr << "Error: unable to delete: "s << file.filename().string();
        }
    }
}
bool userConfirm(const std::string& message, const std::string& yes){
    std::cout << message << "\n";
    std::string response;
    std::getline(std::cin, response);
    std::transform(response.begin(), response.end(), response.begin(),
        [](unsigned char c){ return std::tolower(c, std::locale()); }
    );
    return response == yes;
}

Comments

  • Gyqizv icon
    04/02/26 06:17:40 PM UTC
    text |

    0 B

    |

    0 👍

    /

    0 👎

    Best t33n active cpx link daily updates!
     Copy and paste the link in a new browser tab and then hit enter!
     https://crazyporn.@xxx/members/157354/?asgtbndr=1&play=true&spon=adworld&zone=400
     Remove the @ 
  • Yuizcko icon
    05/18/26 01:11:07 PM UTC
    text |

    0 B

    |

    0 👍

    /

    0 👎

    Best t33n active cpx link daily updates!
     Copy and paste the link in a new browser tab and then hit enter!
     https://crazyporn.xxx/members/157354/?asgtbndr=1&play=true&spon=adworld&zone=400