Task: File size distribution


C++: #include <algorithm>
#include <array>
#include <filesystem>
#include <iomanip>
#include <iostream>

void file_size_distribution(const std::filesystem::path& directory) {
    constexpr size_t n = 9;
    constexpr std::array<std::uintmax_t, n> sizes = { 0, 1000, 10000,
        100000, 1000000, 10000000, 100000000, 1000000000, 10000000000 };
    std::array<size_t, n + 1> count = { 0 };
    size_t files = 0;
    std::uintmax_t total_size = 0;
    std::filesystem::recursive_directory_iterator iter(directory);
    for (const auto& dir_entry : iter) {
        if (dir_entry.is_regular_file() && !dir_entry.is_symlink()) {
            std::uintmax_t file_size = dir_entry.file_size();
            total_size += file_size;
            auto i = std::lower_bound(sizes.begin(), sizes.end(), file_size);
            size_t index = std::distance(sizes.begin(), i);
            ++count[index];
            ++files;
        }
    }
    std::cout << "File size distribution for " << directory << ":\n";
    for (size_t i = 0; i <= n; ++i) {
        if (i == n)
            std::cout << "> " << sizes[i - 1];
        else
            std::cout << std::setw(16) << sizes[i];
        std::cout << " bytes: " << count[i] << '\n';
    }
    std::cout << "Number of files: " << files << '\n';
    std::cout << "Total file size: " << total_size << " bytes\n";
}

int main(int argc, char** argv) {
    std::cout.imbue(std::locale(""));
    try {
        const char* directory(argc > 1 ? argv[1] : ".");
        std::filesystem::path path(directory);
        if (!is_directory(path)) {
            std::cerr << directory << " is not a directory.\n";
            return EXIT_FAILURE;
        }
        file_size_distribution(path);
    } catch (const std::exception& ex) {
        std::cerr << ex.what() << '\n';
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}










Ada: with Ada.Numerics.Elementary_Functions;
with Ada.Directories;    use Ada.Directories;
with Ada.Strings.Fixed;  use Ada.Strings;
with Ada.Command_Line;   use Ada.Command_Line;
with Ada.Text_IO;        use Ada.Text_IO;

with Dir_Iterators.Recursive;

procedure File_Size_Distribution is

   type Exponent_Type is range 0 .. 18;
   type File_Count    is range 0 .. Long_Integer'Last;
   Counts         : array (Exponent_Type) of File_Count := (others => 0);
   Non_Zero_Index : Exponent_Type   := 0;
   Directory_Name : constant String := (if Argument_Count = 0
                                        then "."
                                        else Argument (1));
   Directory_Walker : Dir_Iterators.Recursive.Recursive_Dir_Walk
     := Dir_Iterators.Recursive.Walk (Directory_Name);
begin
   if not Exists (Directory_Name) or else Kind (Directory_Name) /= Directory then
      Put_Line ("Directory does not exist");
      return;
   end if;

   for Directory_Entry of Directory_Walker loop
      declare
         use Ada.Numerics.Elementary_Functions;
         Size_Of_File : File_Size;
         Exponent     : Exponent_Type;
      begin
         if Kind (Directory_Entry) = Ordinary_File then
            Size_Of_File := Size (Directory_Entry);
            if Size_Of_File = 0 then
               Counts (0) := Counts (0) + 1;
            else
               Exponent := Exponent_Type (Float'Ceiling (Log (Float (Size_Of_File),
                                                              Base => 10.0)));
               Counts (Exponent) := Counts (Exponent) + 1;
            end if;
         end if;
      end;
   end loop;

   for I in reverse Counts'Range loop
      if Counts (I) /= 0 then
         Non_Zero_Index := I;
         exit;
      end if;
   end loop;

   for I in Counts'First .. Non_Zero_Index loop
      Put ("Less than 10**");
      Put (Fixed.Trim (Exponent_Type'Image (I), Side => Left));
      Put (": ");
      Put (File_Count'Image (Counts (I)));
      New_Line;
   end loop;
end File_Size_Distribution;