Win API to compare 2 directories - winapi

Is there an existing Win API which can be used to compare two different directories, find the extra files in destination directory and print them? Or if there is any other way. I am trying to compare them based on file size and file name.
I tried to find out on internet, but could not find any relevant links.
Could you please help here?
Thanks in advance for your help!

I suppose you don't need to recursively compare the folders contained.
#include <windows.h>
#include <iostream>
#include <algorithm>
#include <list>
#include <atlstr.h>
#include <set>
#include <iterator>
using namespace std;
std::set<CString> allFilesinDir(CString dir)
{
std::set<CString> s;
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile(dir, &ffd);
// List all the files in the directory with some info about them.
if (hFind == INVALID_HANDLE_VALUE) {
return s;
}
do
{
CString filename = ffd.cFileName;
s.insert(filename);
} while (FindNextFile(hFind, &ffd) != 0);
return s;
}
int main()
{
CString dir1 = _T("path1\\*");
CString dir2 = _T("path2\\*");
std::set<CString> s1 = allFilesinDir(dir1);
std::set<CString> s2 = allFilesinDir(dir2);
std::set<CString> s3{};
std::set_difference(s2.begin(), s2.end(), s1.begin(), s1.end(), std::inserter(s3,s3.end()));
for (const CString &s4 : s3)
{
int remove1 = dir2.Find(_T("*"));
dir2 = dir2.Left(remove1);
CString FilePath = dir2 + s4;
if (GetFileAttributes(FilePath) == FILE_ATTRIBUTE_DIRECTORY)
{
SHFILEOPSTRUCT DirRemove;
DirRemove.fFlags = FOF_NOCONFIRMATION;
DirRemove.hNameMappings = NULL;
DirRemove.hwnd = NULL;
DirRemove.lpszProgressTitle = NULL;
DirRemove.pFrom = FilePath;
DirRemove.pTo = NULL;
DirRemove.wFunc = FO_DELETE;
SHFileOperation(&DirRemove);
}
else
DeleteFile(FilePath);
}
}
If you only need to compare different normal files, not folders, ignore the final processing of folders in the code.

Related

boost filesystem making long path under windows using \\?\

it is so simple but i can not make it work and i do not know why??
i just want to make directory with long path.
i add \\\\?\\ to E:\\... to make it as win api says .
but in vain.....nothing but error.
i tried \\?\ and \?\ with no success.
this is the code :
// boost_create_directory.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <fstream>
#include <string>
#include <time.h>
#include <stdio.h>
#include <ctime>
#include <iostream>
#include <map> //Needed to use the std::map class.
//#include "symbols_array2.h"
//#include "functions.h"
#include <boost/filesystem.hpp>
//#include <curl/curl.h>
#include <stdio.h>
#include <stdlib.h>
////#include <filesystem>
////namespace fs = std::filesystem;
//#define DOWNLOAD_ALL true
int main()
{
using namespace std;
using namespace boost::filesystem;
//string localpath, binlocalfile, localfile;
string localpath = "\\\\?\\E:\\instruments\\symbol\\year\\month\\day\\";
//boost::filesystem::path abs_localpath;
////string localpath = "E:\\instruments\\symbol\\year\\month\\day\\";
boost::filesystem::path abs_localpath(localpath) ;
////string localpath = "\\\\?\\E:\\instruments\\symbol\\year\\month\\day\\";
////boost::filesystem::path abs_localpath("\\\\?\\E:\\instruments\\symbol\\year\\month\\day\\");
////string localpath = "E:/i/";
////boost::filesystem::path abs_localpath("\\?\E:\instruments\symbol\year\month\day\\");
////boost::filesystem::path path_argument(localpath);
////boost::filesystem::path path_native(path_argument.make_preferred());
////boost::filesystem::path abs_localpath(absolute(path_native));
//binlocalfile = localpath + "\\hourh_ticks.bin";
//localfile = localpath + "\\hourh_ticks.bi5";
//abs_localpath = boost::filesystem::absolute(localpath.c_str());
//abs_localpath = localpath;
//if (!boost::filesystem::exists(abs_localpath))
//{
//boost::filesystem::path abs_localpath;
//cout << current_path().string() << endl;
//cout << abs_localpath << endl;
//boost::filesystem::create_directory(abs_localpath);
for (int z = 0; z < 10; z++)
{
if (boost::filesystem::create_directory(abs_localpath)) {
std::cout << "Success making new directory" << "\n";
//boost::filesystem::permissions(abs_localpath, perms_mask);
}
//localpath = localpath + "\\instruments\\symbol\\year\\month\\day";
abs_localpath / "instruments\\symbol\\year\\month\\day\\";
////abs_localpath /= "\instruments\symbol\year\month\day\";
}
//mkdir($localpath, 0777, true);
//}
boost::filesystem::path path("\\?\\E:\\MyStuff\\");
boost::filesystem::create_directory(path);
return 0;
}
i hope to find answer here.thanks in advance.
it was my fault .the create_directory function make single directory if path is already created and return with error if path is missing,So i needed create_directories the plural version make all missing elements of path and voila.
i wish they change these names to create_single_directory or create_target_directory and change the plural to create_path_directories

how to find characters in a string and then remove them if they match a particular character?

/* I have to find character and remove them, based on the character it has to go inside the if/else if condition. I am facing difficulty in getting inside the else if condition */
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <string>
using namespace std;
int main() {
int fut = 0, spd =0;
std::string symbol = "PGSh/d TWOGK h/d"; //it will contain either 'h/d' or '/'
std::string str = "h/d";
std::string str1 = "/";
if(symbol.find(str)) //if it finds "h/d" then it belongs to future
{
++fut; //even one count is enough
boost::erase_all(symbol, "h/d");
std::cout<<"Future Instrument "<<std::endl;
}
else if(symbol.find(str1)) //if it finds "/" then it belongs to spread
{
++spd; //even one count is enough
boost::erase_all(symbol, "//");
std::cout<<"Spread Instrument "<<std::endl;
}
boost::erase_all(symbol, " ");
boost::to_upper(symbol);
std::cout<<symbol<<std::endl;
return 0;
}

gcc using unlink and readdir, 7 days old files needs to be deleted

Using this code fetched from google.
#include <dirent.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
struct dirent *entry;
DIR *dp;
chdir("/mnt/shared");
dp = opendir(".");
while( (entry = readdir(dp)) != NULL ) {
if ( strcmp(entry->d_name, ".") &&strcmp(entry->d_name, "..") ){
unlink(entry->d_name);
}
}
}`
In this could it be possible to delete files older than 7 days from the current date?
In perl i tried as follows, but wondering this could be achived with your help?
my $now = time();
my $DATEAGE = 60*60*24*7;
for my $file (#file_list) {
my #stats = stat($file);
if ($now-$stats[9] > $DATEAGE) {
print "$file\n";}
Build the full string of the file and use several syscalls(2) (notably stat(2)) ; read Advanced Linux Programming
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
struct dirent *entry;
DIR *dp;
time_t weekago;
time(&weekago);
weekago -= 86400*7;
dp = opendir("/mnt/shared");
if (!dp) { perror("/mnt/shared"); exit(EXIT_FAILURE); };
while( (entry = readdir(dp)) != NULL ) {
if ( strcmp(entry->d_name, ".")
&& strcmp(entry->d_name, "..") ){
char buf[256];
if (snprintf(buf, sizeof(buf),
"/mnt/shared/%s", entry->d_name)
>=sizeof(buf))
{ fprintf(stderr, "too long path %s\n", buf);
exit(EXIT_FAILURE);
};
struct stat st;
if (stat(buf,&st)) {
perror(buf);
exit(EXIT_FAILURE);
};
if ((st.st_mode & S_IFMT) == S_IFREG // a plain file
&& (st.st_mtime < weekago))
{
if (remove(buf)) perror(buf);
}
}
}
My untested code above is imperfect (and not very well indented): it don't handle file paths wider than 255. But you could improve it, e.g. using asprintf(3) to build the path in heap (then you'll need to free it).
Practically speaking, use find(1). If you need to recurse in a file tree in C, use nftw(3)

sort files by ascii order

I'm trying to code a simple function to sort the content of a directory. The Thing is, it comes out in alphabetical order, regardless of uppercase or lowercase. I'd like to sort this content in ASCII order.
example: I got 4 files, named Art, boat, Cat and donkey. My actual code sort them in this order, while i'd like to get Art, Cat, boat and donkey.
void list_dir(char *str){
DIR *rep = NULL;
struct dirent* read_file = NULL;
rep = opendir(str);
if (!rep)
{
ft_putstr("ft_ls: ");
perror(str);
ft_putchar('\n');
}
while((read_file = readdir(rep)) != NULL)
{
if (read_file->d_name[0] != '.')
{
ft_putstr(read_file->d_name);
ft_putchar('\n');
}
}
}
readdir(3) does not normally sort at all, it lists the entries in directory order. If the list is sorted, either the files were created sorted, or the OS sorts them.
In order to sort the output yourself, put the list of names into an array then sort it e.g. with qsort(3) and strcmp(3).
Alternatively, just pipe the output through sort(1). Do make sure that the LC_COLLATION environment variable is set proper. For example, run ./yourprogram | (unset LC_ALL; LC_CTYPE=en_US.UTF-8 LC_COLLATE=C sort).
By calling scandir with user defined filter & comparator is a simple solution imho. Here is the code:
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static int my_dir_filter(const struct dirent* dir);
static int my_dir_comparator(const struct dirent**, const struct dirent**);
int main(int argc, char* const* argv) {
struct dirent** ent_list_ = NULL;
int r = scandir(".", &ent_list_, my_dir_filter, my_dir_comparator);
for (int i = 0; i < r; ++i)
printf("No. %-3d [%s]\n", i + 1, ent_list_[i]->d_name);
for (int i = 0; i < r; ++i)
free(ent_list_[i]);
free(ent_list_);
return r < 0 ? 1 : 0;
}
int my_dir_filter(const struct dirent* dir) {
return (dir->d_type == DT_REG) ? 1 : 0;
}
int my_dir_comparator(const struct dirent** lhs, const struct dirent** rhs) {
return strcasecmp((*lhs)->d_name, (*rhs)->d_name);
}
And test result:
$ ls|LANG=C sort ## in ASCII order
Art
Cat
boat
donkey
$ ../a.out ## in my_dir_comparator order
No. 1 [Art]
No. 2 [boat]
No. 3 [Cat]
No. 4 [donkey]

boost.log auto_flush files are not stored when app is crashed

Recently I started to play with boost.log, and bumped into an issue that if an unhanded exception is thrown no log messages are written to the log file. I am using rolling text files and auto-flash option is set on.
Here is the modified source from the samples:
#include <stdexcept>
#include <string>
#include <iostream>
#include <fstream>
#include <functional>
#include <boost/ref.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/barrier.hpp>
#include <boost/log/common.hpp>
#include <boost/log/filters.hpp>
#include <boost/log/formatters.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/utility/empty_deleter.hpp>
#include <boost/log/utility/record_ordering.hpp>
namespace logging = boost::log;
namespace attrs = boost::log::attributes;
namespace src = boost::log::sources;
namespace sinks = boost::log::sinks;
namespace fmt = boost::log::formatters;
namespace keywords = boost::log::keywords;
using boost::shared_ptr;
using namespace boost::gregorian;
enum
{
LOG_RECORDS_TO_WRITE = 100,
LOG_RECORDS_TO_WRITE_BEFORE_EXCEPTION = 10,
THREAD_COUNT = 10
};
BOOST_LOG_DECLARE_GLOBAL_LOGGER(test_lg, src::logger_mt)
//! This function is executed in multiple threads
void thread_fun(boost::barrier& bar)
{
// Wait until all threads are created
bar.wait();
// Here we go. First, identify the thread.
BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::thread::id, boost::this_thread::get_id());
// Now, do some logging
for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i)
{
BOOST_LOG(get_test_lg()) << "Log record " << i;
if(i > LOG_RECORDS_TO_WRITE_BEFORE_EXCEPTION)
{
BOOST_THROW_EXCEPTION(std::exception("unhandled exception"));
}
}
}
int main(int argc, char* argv[])
{
try
{
typedef sinks::synchronous_sink< sinks::text_file_backend > file_sink;
shared_ptr< file_sink > sink(new file_sink(
keywords::file_name = L"%Y%m%d_%H%M%S_%5N.log", // file name pattern
keywords::rotation_size = 10 * 1024 * 1024, // rotation size, in characters
keywords::auto_flush = true // make each log record flushed to the file
));
// Set up where the rotated files will be stored
sink->locked_backend()->set_file_collector(sinks::file::make_collector(
keywords::target = "log" // where to store rotated files
));
// Upon restart, scan the target directory for files matching the file_name pattern
sink->locked_backend()->scan_for_files();
sink->locked_backend()->set_formatter(
fmt::format("%1%: [%2%] [%3%] - %4%")
% fmt::attr< unsigned int >("Line #")
% fmt::date_time< boost::posix_time::ptime >("TimeStamp")
% fmt::attr< boost::thread::id >("ThreadID")
% fmt::message()
);
// Add it to the core
logging::core::get()->add_sink(sink);
// Add some attributes too
shared_ptr< logging::attribute > attr(new attrs::local_clock);
logging::core::get()->add_global_attribute("TimeStamp", attr);
attr.reset(new attrs::counter< unsigned int >);
logging::core::get()->add_global_attribute("Line #", attr);
// Create logging threads
boost::barrier bar(THREAD_COUNT);
boost::thread_group threads;
for (unsigned int i = 0; i < THREAD_COUNT; ++i)
threads.create_thread(boost::bind(&thread_fun, boost::ref(bar)));
// Wait until all action ends
threads.join_all();
return 0;
}
catch (std::exception& e)
{
std::cout << "FAILURE: " << e.what() << std::endl;
return 1;
}
}
Source is compiled under Visual Studio 2008. boost.log compiled for boost 1.40.
Any help is highly appreciated.
Check to see if the log file is in the current working directory of the process, rather than the specified file collector target directory ("log" in your sample code). Additionally, you will probably want to specify a directory for the sink "file_name" pattern.
As "JQ" notes, don't expect to see any logging post-exception.

Resources