SHARE
TWEET

FilteredDeleter

ulfben Jan 2nd, 2018 (edited) 80 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // FilteredDeleter deletes all files in the target folder, which does not exist in the source folder.
  2. // It only looks at file names and ignores file extension.
  3.  
  4. // It solves a niche problem for me, after photographing big events.
  5. // I shoot JPG+RAW. RAW files are enormously slow to flip through.
  6. // Thus, when I manually cull the set - throwing out all unusable photos -
  7. // -I only look at the JPGs. Leaving me with:
  8. //    -a (source) folder of curated (JPG) files (<1000s of files, <10GB)</li>
  9. //    -a (target) folder with *all* (RAW) files (>1000s of files, >50GB)</li>
  10. // This program deletes all the unneeded RAW files.
  11. // TODO: implement the command line interface
  12. #include <algorithm>
  13. #include <filesystem>
  14. #include <cctype>
  15. #include <iterator>
  16. #include <iostream>
  17. #include <string>
  18. #include "ProgramOptions.h"
  19. using namespace std::string_literals;
  20. namespace fs = std::experimental::filesystem;
  21. using PathList = std::vector<fs::path>;
  22. PathList getFileList(const fs::path& dir); //returns a sorted list of file paths
  23. PathList getDifference(const PathList& source, const PathList& target);
  24. bool userConfirm(const std::string& message, const std::string& yes = "y"s);
  25. void deleteFiles(const PathList& toRemove);
  26. template<typename C, typename T = fs::path> void printEach(const C& v);
  27.  
  28. int main(int argc, char* argv[]){
  29.     const ProgramOptions opts(argc, argv);     
  30.     const auto source = fs::path{R"(Y:\Temp\WeddingPhotosChosen)"}; //Q&D: hardcoding paths...
  31.     const auto target = fs::path{R"(Y:\Temp\WeddingPhotosRAW)"}; //TODO: use the ProgramOptions command line interface
  32.     const PathList sourceFiles = getFileList(source);
  33.     const PathList targetFiles = getFileList(target);
  34.     const PathList toRemove = getDifference(sourceFiles, targetFiles); 
  35.     printEach(toRemove);       
  36.     if(userConfirm("Press Y to delete these files."s)){
  37.         deleteFiles(toRemove);
  38.     }
  39.     userConfirm("Done! Double-check the error output\n\tbefore you press any key to quit."s);
  40.     return 0;
  41. }
  42.  
  43. PathList getDifference(const PathList& sourceFiles, const PathList& targetFiles){
  44.     //Copies the elements from the sorted range [targets)
  45.     //which are not found in the sorted range [source)
  46.     //to the list toRemove.
  47.     PathList toRemove;
  48.     std::set_difference(targetFiles.begin(), targetFiles.end(),
  49.         sourceFiles.begin(), sourceFiles.end(),
  50.         std::inserter(toRemove, toRemove.begin()),
  51.         [](const fs::path& source, const fs::path& target){
  52.             return source.stem() < target.stem(); //comparing only filenames
  53.         }
  54.     );
  55.     return toRemove;
  56. }
  57. template<typename C, typename T>
  58. void printEach(const C& v){
  59.     std::copy(std::begin(v), std::end(v), std::ostream_iterator<T>{std::cout, ",\n"});
  60.     std::cout << '\n';
  61. }
  62. PathList getFileList(const fs::path& dir){
  63.     PathList out;
  64.     if(!fs::exists(dir) || !fs::is_directory(dir)){
  65.         return out;
  66.     }
  67.     for(const auto& entry : fs::directory_iterator(dir)){
  68.         if(fs::is_regular_file(entry.status())){
  69.             out.push_back(entry.path());
  70.         }
  71.     }
  72.     std::sort(out.begin(), out.end());
  73.     return out;
  74. }
  75. void deleteFiles(const PathList& toRemove){
  76.     for(const auto& file : toRemove){
  77.         if(!is_regular_file(file)){
  78.             std::cerr << "Warning: skipping non-file: "s << file.filename().string();
  79.             continue;
  80.         }
  81.         if(!fs::remove(file)){
  82.             std::cerr << "Error: unable to delete: "s << file.filename().string();
  83.         }
  84.     }
  85. }
  86. bool userConfirm(const std::string& message, const std::string& yes){
  87.     std::cout << message << "\n";
  88.     std::string response;
  89.     std::getline(std::cin, response);
  90.     std::transform(response.begin(), response.end(), response.begin(),
  91.         [](unsigned char c){ return std::tolower(c, std::locale()); }
  92.     );
  93.     return response == yes;
  94. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top