-1

i need to control if a folder defined by a path is full of folders, if those folders are too much i need to delete, for example half of them, from the older one the newest one. Practically i need to make space for future folders.

void fCID(long pThreadId)
{
 ULARGE_INTEGER rFreeBytesAvailable, rTotalNumberOfBytes, rTotalNumberOfFreeBytes;
 if(sc.LB.TMCI && sc.LB.ISM == 1)
 {
   for(10000000000;10000000000 > sd;sd--) //wrong, i'm looking for it
   {
    if (::GetDiskFreeSpaceEx (NULL, &rFreeBytesAvailable, &rTotalNumberOfBytes, 
      &rTotalNumberOfFreeBytes))
      {
       if (rFreeBytesAvailable.QuadPart > 10000000000)     //10gb
        {
         fAFOZA("C:\\S\\H1\\CA");   //function zip   
        }
       else
       {
        sd=sd - 50% of (LA); //sd = space disposable
       }
      }
    }
  }
else  
{
fDFOP(where.Trace_C_P);  //not interesting
fDFOP(where.Trace_C_CL_P); //not interesting
}
}

This code is only an idea

ULARGE_INTEGER rFreeBytesAvailable, rTotalNumberOfBytes, 
rTotalNumberOfFreeBytes;
if(sc.LB.TMCI && sc.LB.ISM == 1)
{
if (::GetDiskFreeSpaceEx ("C:\\S\\H1\\CA\\LA", &rFreeBytesAvailable, &rTotalNumberOfBytes, &rTotalNumberOfFreeBytes))
{
  do
    {
      fDFOP("C:\\S\\H1\\CA\\LA"); //this function deletes what's inside the path
    }while(rFreeBytesAvailable.QuadPart == 10000000000)
    if (rFreeBytesAvailable.QuadPart > 10000000000)     //10gb
    {
      fAFOZA("C:\\S\\H1\\CA");//this one makes a zip 
    }
 }
}

this is another possible implementation maybe

rustyx
  • 80,671
  • 25
  • 200
  • 267
codroipo
  • 155
  • 12
  • This question seems OS specific, but there's no OS tag. – tadman May 18 '20 at 07:28
  • why OS specific?because i'm trying to work with folders? – codroipo May 18 '20 at 07:30
  • `GetDiskFreeSpaceEx` is not a C++ function, it's an OS one. – tadman May 18 '20 at 07:30
  • you are right, fixed – codroipo May 18 '20 at 07:33
  • Please tag with the actual operating system you're using. Is this Windows? If so then `[win32]` or at least `[windows]`. – tadman May 18 '20 at 07:33
  • done, but can you help me?have you got any idea? – codroipo May 18 '20 at 07:38
  • 1
    Do you need to do this with C++? You could probably just use task scheduling and write a simple batch script to delete old files. Maybe something like [this](https://pureinfotech.com/delete-files-older-than-days-windows-10/) – dreamlax May 18 '20 at 08:01
  • i need to do it from c++ :( – codroipo May 18 '20 at 08:09
  • i want to check how much disposable space there is into a folder defined by a path... if that space is less than 10gb, i want to delete (choice 1: older folders or choice 2: a percentage of the older files) – codroipo May 18 '20 at 08:50
  • whith the GetDiskFreeSpaceEx i want to check how much free space there is into this path ''C:\\S\\H1\\CA\\LA", i've read that only if u leave it to NULL it will operate on the default disk – codroipo May 18 '20 at 08:56
  • 1
    So after GetDiskFreeSpaceEx you know how much space you need to free up. Next step is to [list the files](https://stackoverflow.com/questions/41404711/how-to-list-files-in-a-directory-using-the-windows-api), sort by descending modified time (?) and delete the oldest ones until you reach the amount you need to free up. – rustyx May 18 '20 at 09:09
  • mmmmmmm.... didn't tought to that solution....it might be the best but no idead on how to implement it into my code... – codroipo May 18 '20 at 09:38
  • `for(10000000000;10000000000 > sd;sd--)` what is this??? Where is `sd` initialized? – Jabberwocky May 18 '20 at 10:02
  • If you find the Winapi for reading directories cumbersome, you could use [std::filesystem::recursive_directory_iterator](https://en.cppreference.com/w/cpp/filesystem/recursive_directory_iterator) and put the files found in a [std::set](https://en.cppreference.com/w/cpp/container/set) sorted on [std::filesystem::last_write_time](https://en.cppreference.com/w/cpp/filesystem/last_write_time) (+ path). Deleting the oldest would then just be a matter of [std::filesystem::remove](https://en.cppreference.com/w/cpp/filesystem/remove)ing the first entries in the set. – Ted Lyngmo May 18 '20 at 10:49
  • @Jabberwocky it is only an example – codroipo May 18 '20 at 11:05
  • @TedLyngmo ehm... not so skilled... sorry i think that inside your answer is what i'm searching for but...a little explaination? – codroipo May 18 '20 at 11:07
  • @codroipo Ok, I made an answer out of it. – Ted Lyngmo May 18 '20 at 16:23

1 Answers1

2

If you want to remove the oldest files in a directory structure to reclaim a certain amount of space, you could use the C++17 std::filesystem library class recursive_directory_iterator and the functions last_write_time and remove from the same library.

Example:

#include <cstdint>
#include <filesystem>
#include <set>
#include <string>
#include <system_error>
#include <tuple>

namespace fs = std::filesystem;

// a class containing the interesting information about each file
struct file {
    fs::path path;
    std::uintmax_t file_size;
    std::filesystem::file_time_type write_time;

    // An operator< to be able to sort files in this order:
    //  ascending write_time
    //  decending file_size (to remove the biggest of two files with the same write_time)
    //  ascending path
    bool operator<(const file& rhs) const {
        return
            std::tie(write_time, rhs.file_size, path) <
            std::tie(rhs.write_time, file_size, rhs.path);
    }
};

// A function to traverse a directory structure, collect file names, age and sizes
// and to remove the oldest until "bytes_to_remove" bytes have been removed
std::uintmax_t rm_old_files(const std::wstring& dir, std::uintmax_t bytes_to_remove) {
    std::uintmax_t bytes_removed = 0;
    std::set<file> files; // the set will sort file entries with the oldest first

    // collect all regular files in the directory structure starting at "dir"
    for (const fs::directory_entry& de : fs::recursive_directory_iterator(dir)) {
        if (de.is_regular_file()) {
            files.emplace(file{de, de.file_size(), fs::last_write_time(de)});
        }
    }

    // remove files until at least "bytes_to_remove" bytes have been removed
    std::error_code ec; // unread but used to prevent exceptions in fs::remove
    for (auto const& [path, file_size, write_time] : files) {
        std::wcout << L"removing " << path << L'\n';

        /* uncomment this part when you've made sure that it'll
           remove the correct files.
        if (fs::remove(path, ec)) {
            bytes_removed += file_size;
            if (bytes_removed >= bytes_to_remove) break;
        }
        */
    }

    return bytes_removed;
}

Example usage:

std::wstring dir = L"C:\\S\\H1\\CA\\LA";
ULARGE_INTEGER FreeBytesAvailableToCaller;
ULARGE_INTEGER TotalNumberOfBytes;
ULARGE_INTEGER TotalNumberOfFreeBytes;

if (GetDiskFreeSpaceExW(dir.c_str(), &FreeBytesAvailableToCaller,
                                     &TotalNumberOfBytes, 
                                     &TotalNumberOfFreeBytes)) {
    // if less than half the total number of bytes are available,
    // execute rm_old_files to try to make at least half available.
    if (FreeBytesAvailableToCaller.QuadPart < TotalNumberOfBytes.QuadPart/2) {
        auto bytes_removed = 
            rm_old_files(dir, TotalNumberOfBytes.QuadPart/2 -
                              FreeBytesAvailableToCaller.QuadPart);
        std::wcout << L"removed " << bytes_removed << L" bytes\n";
    }
}

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • this is some serious code, i've only a question about it... is it a modified version of the code that i've written above?...cause i can't find myself in it... you diserve a better explaination... i need to incorporate the management of the older files into a function that i don't want and can't touch... this magnificent code i've no doubt that is able to do what i need but it can't fit into my code... don't know what i can do... – codroipo May 19 '20 at 07:36
  • @codroipo This is an example of an implementation based on the suggestions I made in the comment about using the `std::filesystem` functionality to traverse the directory structure to remove the oldest files. You could also use the WinAPI functions suggested by rustyx but since you said "_it might be the best but no idead on how to implement it into my code_" I thought this would be easier. Another benefit is that it's using standard C++17 functionality. You'd need to call `GetDiskFreeSpaceExW(dir,..` to calculate how much space you need to free up and then call `rm_old_files` with the result. – Ted Lyngmo May 19 '20 at 08:22
  • i haven't understood the last phrases – codroipo May 19 '20 at 12:11
  • 1
    @codroipo In your question it looks like you call `GetDiskFreeSpaceEx` to get the available sizes and the total size for a certain directory. Is that correct? In that case you could do something like `if(FreeBytesAvailableToCaller.QuadPart < TotalNumberOfBytes.QuadPart/2) rm_old_files(directory, TotalNumberOfBytes.QuadPart/2 -FreeBytesAvailableToCaller.QuadPart);` to try to make half the total disk space available. – Ted Lyngmo May 19 '20 at 12:23
  • you mean instead of the GetDiskFreeSpaceEx – codroipo May 19 '20 at 13:47
  • 1
    @codroipo No, first you call `GetDiskFreeSpaceEx(directory,...);` then and use the result to calculate how much space you need to free up. You use the result of that calculation with `rm_old_files`. I've added an example for that (but I have no Windows machine here to test it). – Ted Lyngmo May 19 '20 at 14:13
  • @codroipo I just tested the example usage code that I added to my answer and can confirm that it works. – Ted Lyngmo May 19 '20 at 17:45
  • @ Ted Lyngmo so the final usage is a combo of the first part of code and the second or from the first code i've to use only the rm_old_files? – codroipo May 20 '20 at 07:58
  • 1
    @codroipo It's a combo. You call `GetDiskFreeSpaceExW` to find out the current status, make calculations for how much (if any) you need to remove and then call `rm_old_files` to try to remove that much. – Ted Lyngmo May 20 '20 at 08:00
  • the functionality of all of it is still foggy to me...i know that it may works first shot but without understanding i'm a little bit scared of – codroipo May 20 '20 at 08:13
  • for example mine function are like "void ffunction(char *Path)" and yours are "std::uintmax_t rm_old_files(const std::wstring& dir, std::uintmax_t bytes_to_remove) " – codroipo May 20 '20 at 08:14
  • @codroipo Is there any particular part that you'd like me to explain in more detail? – Ted Lyngmo May 20 '20 at 08:14
  • is it possible to convert your type into mine? it will be more clear to me to understand what i'm completley doing – codroipo May 20 '20 at 08:14
  • this is a hotspot? "if (fs::remove(path, ec)) { bytes_removed += file_size; if (bytes_removed >= bytes_to_remove) break; }" – codroipo May 20 '20 at 08:15
  • and what do i need this for? – codroipo May 20 '20 at 08:18
  • // a class containing the interesting information about each file struct file { fs::path path; std::uintmax_t file_size; std::filesystem::file_time_type write_time; // An operator< to be able to sort files in this order: // ascending write_time // decending file_size (to remove the biggest of two files with the same write_time) // ascending path bool operator<(const file& rhs) const { return std::tie(write_time, rhs.file_size, path) < std::tie(rhs.write_time, file_size, rhs.path); } }; – codroipo May 20 '20 at 08:18
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/214241/discussion-between-ted-lyngmo-and-codroipo). – Ted Lyngmo May 20 '20 at 08:18