Чтение и группировка файлов из каталога в Zig

У меня есть папка с изображениями, содержащая несколько тысяч изображений в трех разных форматах: png, jpg и webp. Например: boat.png, boat.webp, plane.jpg, plane.png, plane.webp.

Я решил изучить Zig и написать программу, которая будет проходить через этот каталог и удалять все, кроме самого маленького файла с определенным «базовым именем» (например, лодка или самолет).

Имейте в виду, да, я пробовал ИИ. Они недостаточно знают Зиг

Я выполнил большую часть группировки, но меня беспокоит результат:

Lets open the ../tests directory
File DSC_0031.webp (fs.File.Kind.file)
Filename DSC_0031.webp
Basename: DSC_0031
File DSC_0031.png (fs.File.Kind.file)
Filename DSC_0031.png
Basename: DSC_0031
File DSC_0025.png (fs.File.Kind.file)
Filename DSC_0025.png
Basename: DSC_0025
File DSC_0025.JPG (fs.File.Kind.file)
Filename DSC_0025.JPG
Basename: DSC_0025
File DSC_0031.JPG (fs.File.Kind.file)
Filename DSC_0031.JPG
Basename: DSC_0031
File DSC_0027.webp (fs.File.Kind.file)
Filename DSC_0027.webp
Basename: DSC_0027
File DSC_0050.webp (fs.File.Kind.file)
Filename DSC_0050.webp
Basename: DSC_0050
File DSC_0007.webp (fs.File.Kind.file)
Filename DSC_0007.webp
Basename: DSC_0007
File DSC_0027.JPG (fs.File.Kind.file)
Filename DSC_0027.JPG
Basename: DSC_0027
File DSC_0033.JPG (fs.File.Kind.file)
Filename DSC_0033.JPG
Basename: DSC_0033
File DSC_0033.png (fs.File.Kind.file)
Filename DSC_0033.png
Basename: DSC_0033
File DSC_0027.png (fs.File.Kind.file)
Filename DSC_0027.png
Basename: DSC_0027
File DSC_0046.webp (fs.File.Kind.file)
Filename DSC_0046.webp
Basename: DSC_0046
File DSC_0026.png (fs.File.Kind.file)
Filename DSC_0026.png
Basename: DSC_0026
File DSC_0032.png (fs.File.Kind.file)
Filename DSC_0032.png
Basename: DSC_0032
File DSC_0032.JPG (fs.File.Kind.file)
Filename DSC_0032.JPG
Basename: DSC_0032
File DSC_0026.JPG (fs.File.Kind.file)
Filename DSC_0026.JPG
Basename: DSC_0026
File DSC_0036.JPG (fs.File.Kind.file)
Filename DSC_0036.JPG
Basename: DSC_0036
File .DS_Store (fs.File.Kind.file)
Filename .DS_Store
Basename: .DS_Store
File DSC_0036.png (fs.File.Kind.file)
Filename DSC_0036.png
Basename: DSC_0036
File DSC_0037.png (fs.File.Kind.file)
Filename DSC_0037.png
Basename: DSC_0037
File DSC_0047.webp (fs.File.Kind.file)
Filename DSC_0047.webp
Basename: DSC_0047
File DSC_0037.JPG (fs.File.Kind.file)
Filename DSC_0037.JPG
Basename: DSC_0037
File DSC_0006.webp (fs.File.Kind.file)
Filename DSC_0006.webp
Basename: DSC_0006
File DSC_0051.webp (fs.File.Kind.file)
Filename DSC_0051.webp
Basename: DSC_0051
File DSC_0026.webp (fs.File.Kind.file)
Filename DSC_0026.webp
Basename: DSC_0026
File DSC_0035.JPG (fs.File.Kind.file)
Filename DSC_0035.JPG
Basename: DSC_0035
File DSC_0035.png (fs.File.Kind.file)
Filename DSC_0035.png
Basename: DSC_0035
File DSC_0034.png (fs.File.Kind.file)
Filename DSC_0034.png
Basename: DSC_0034
File DSC_0034.JPG (fs.File.Kind.file)
Filename DSC_0034.JPG
Basename: DSC_0034
File DSC_0056.webp (fs.File.Kind.file)
Filename DSC_0056.webp
Basename: DSC_0056
File DSC_0053.JPG (fs.File.Kind.file)
Filename DSC_0053.JPG
Basename: DSC_0053
File DSC_0047.JPG (fs.File.Kind.file)
Filename DSC_0047.JPG
Basename: DSC_0047
File DSC_0047.png (fs.File.Kind.file)
Filename DSC_0047.png
Basename: DSC_0047
File DSC_0053.png (fs.File.Kind.file)
Filename DSC_0053.png
Basename: DSC_0053
File DSC_0040.webp (fs.File.Kind.file)
Filename DSC_0040.webp
Basename: DSC_0040
File DSC_0052.png (fs.File.Kind.file)
Filename DSC_0052.png
Basename: DSC_0052
File DSC_0046.png (fs.File.Kind.file)
Filename DSC_0046.png
Basename: DSC_0046
File DSC_0046.JPG (fs.File.Kind.file)
Filename DSC_0046.JPG
Basename: DSC_0046
File DSC_0052.JPG (fs.File.Kind.file)
Filename DSC_0052.JPG
Basename: DSC_0052
File DSC_0044.JPG (fs.File.Kind.file)
Filename DSC_0044.JPG
Basename: DSC_0044
File DSC_0050.JPG (fs.File.Kind.file)
Filename DSC_0050.JPG
Basename: DSC_0050
File DSC_0050.png (fs.File.Kind.file)
Filename DSC_0050.png
Basename: DSC_0050
File DSC_0044.png (fs.File.Kind.file)
Filename DSC_0044.png
Basename: DSC_0044
File DSC_0037.webp (fs.File.Kind.file)
Filename DSC_0037.webp
Basename: DSC_0037
File DSC_0045.png (fs.File.Kind.file)
Filename DSC_0045.png
Basename: DSC_0045
File DSC_0051.png (fs.File.Kind.file)
Filename DSC_0051.png
Basename: DSC_0051
File DSC_0051.JPG (fs.File.Kind.file)
Filename DSC_0051.JPG
Basename: DSC_0051
File DSC_0045.JPG (fs.File.Kind.file)
Filename DSC_0045.JPG
Basename: DSC_0045
File DSC_0041.JPG (fs.File.Kind.file)
Filename DSC_0041.JPG
Basename: DSC_0041
File DSC_0055.JPG (fs.File.Kind.file)
Filename DSC_0055.JPG
Basename: DSC_0055
File DSC_0036.webp (fs.File.Kind.file)
Filename DSC_0036.webp
Basename: DSC_0036
File DSC_0055.png (fs.File.Kind.file)
Filename DSC_0055.png
Basename: DSC_0055
File DSC_0041.png (fs.File.Kind.file)
Filename DSC_0041.png
Basename: DSC_0041
File DSC_0040.png (fs.File.Kind.file)
Filename DSC_0040.png
Basename: DSC_0040
File DSC_0054.png (fs.File.Kind.file)
Filename DSC_0054.png
Basename: DSC_0054
File DSC_0054.JPG (fs.File.Kind.file)
Filename DSC_0054.JPG
Basename: DSC_0054
File DSC_0040.JPG (fs.File.Kind.file)
Filename DSC_0040.JPG
Basename: DSC_0040
File DSC_0056.JPG (fs.File.Kind.file)
Filename DSC_0056.JPG
Basename: DSC_0056
File DSC_0042.JPG (fs.File.Kind.file)
Filename DSC_0042.JPG
Basename: DSC_0042
File DSC_0042.png (fs.File.Kind.file)
Filename DSC_0042.png
Basename: DSC_0042
File DSC_0056.png (fs.File.Kind.file)
Filename DSC_0056.png
Basename: DSC_0056
File DSC_0057.png (fs.File.Kind.file)
Filename DSC_0057.png
Basename: DSC_0057
File DSC_0043.png (fs.File.Kind.file)
Filename DSC_0043.png
Basename: DSC_0043
File DSC_0041.webp (fs.File.Kind.file)
Filename DSC_0041.webp
Basename: DSC_0041
File DSC_0043.JPG (fs.File.Kind.file)
Filename DSC_0043.JPG
Basename: DSC_0043
File DSC_0057.JPG (fs.File.Kind.file)
Filename DSC_0057.JPG
Basename: DSC_0057
File DSC_0057.webp (fs.File.Kind.file)
Filename DSC_0057.webp
Basename: DSC_0057
File DSC_0039.webp (fs.File.Kind.file)
Filename DSC_0039.webp
Basename: DSC_0039
File DSC_0042.webp (fs.File.Kind.file)
Filename DSC_0042.webp
Basename: DSC_0042
File DSC_0054.webp (fs.File.Kind.file)
Filename DSC_0054.webp
Basename: DSC_0054
File DSC_0059.JPG (fs.File.Kind.file)
Filename DSC_0059.JPG
Basename: DSC_0059
File DSC_0035.webp (fs.File.Kind.file)
Filename DSC_0035.webp
Basename: DSC_0035
File DSC_0059.png (fs.File.Kind.file)
Filename DSC_0059.png
Basename: DSC_0059
File DSC_0058.png (fs.File.Kind.file)
Filename DSC_0058.png
Basename: DSC_0058
File DSC_0058.JPG (fs.File.Kind.file)
Filename DSC_0058.JPG
Basename: DSC_0058
File DSC_0058.webp (fs.File.Kind.file)
Filename DSC_0058.webp
Basename: DSC_0058
File DSC_0059.webp (fs.File.Kind.file)
Filename DSC_0059.webp
Basename: DSC_0059
File DSC_0048.JPG (fs.File.Kind.file)
Filename DSC_0048.JPG
Basename: DSC_0048
File DSC_0048.png (fs.File.Kind.file)
Filename DSC_0048.png
Basename: DSC_0048
File DSC_0034.webp (fs.File.Kind.file)
Filename DSC_0034.webp
Basename: DSC_0034
File DSC_0049.png (fs.File.Kind.file)
Filename DSC_0049.png
Basename: DSC_0049
File DSC_0049.JPG (fs.File.Kind.file)
Filename DSC_0049.JPG
Basename: DSC_0049
File DSC_0055.webp (fs.File.Kind.file)
Filename DSC_0055.webp
Basename: DSC_0055
File DSC_0014.webp (fs.File.Kind.file)
Filename DSC_0014.webp
Basename: DSC_0014
File DSC_0043.webp (fs.File.Kind.file)
Filename DSC_0043.webp
Basename: DSC_0043
File DSC_0038.webp (fs.File.Kind.file)
Filename DSC_0038.webp
Basename: DSC_0038
File DSC_0025.webp (fs.File.Kind.file)
Filename DSC_0025.webp
Basename: DSC_0025
File DSC_0005.JPG (fs.File.Kind.file)
Filename DSC_0005.JPG
Basename: DSC_0005
File DSC_0039.JPG (fs.File.Kind.file)
Filename DSC_0039.JPG
Basename: DSC_0039
File DSC_0005.png (fs.File.Kind.file)
Filename DSC_0005.png
Basename: DSC_0005
File DSC_0039.png (fs.File.Kind.file)
Filename DSC_0039.png
Basename: DSC_0039
File DSC_0033.webp (fs.File.Kind.file)
Filename DSC_0033.webp
Basename: DSC_0033
File DSC_0048.webp (fs.File.Kind.file)
Filename DSC_0048.webp
Basename: DSC_0048
File DSC_0038.png (fs.File.Kind.file)
Filename DSC_0038.png
Basename: DSC_0038
File DSC_0038.JPG (fs.File.Kind.file)
Filename DSC_0038.JPG
Basename: DSC_0038
File DSC_0006.JPG (fs.File.Kind.file)
Filename DSC_0006.JPG
Basename: DSC_0006
File DSC_0006.png (fs.File.Kind.file)
Filename DSC_0006.png
Basename: DSC_0006
File DSC_0044.webp (fs.File.Kind.file)
Filename DSC_0044.webp
Basename: DSC_0044
File DSC_0007.png (fs.File.Kind.file)
Filename DSC_0007.png
Basename: DSC_0007
File DSC_0007.JPG (fs.File.Kind.file)
Filename DSC_0007.JPG
Basename: DSC_0007
File DSC_0005.webp (fs.File.Kind.file)
Filename DSC_0005.webp
Basename: DSC_0005
File DSC_0052.webp (fs.File.Kind.file)
Filename DSC_0052.webp
Basename: DSC_0052
File DSC_0053.webp (fs.File.Kind.file)
Filename DSC_0053.webp
Basename: DSC_0053
File DSC_0045.webp (fs.File.Kind.file)
Filename DSC_0045.webp
Basename: DSC_0045
File DSC_0014.JPG (fs.File.Kind.file)
Filename DSC_0014.JPG
Basename: DSC_0014
File DSC_0014.png (fs.File.Kind.file)
Filename DSC_0014.png
Basename: DSC_0014
File DSC_0049.webp (fs.File.Kind.file)
Filename DSC_0049.webp
Basename: DSC_0049
File DSC_0032.webp (fs.File.Kind.file)
Filename DSC_0032.webp
Basename: DSC_0032

   (
   DSC_0031.png
   DSC_0031.JPG

   (
   DSC_0025.JPG

   (
   DSC_0027.JPG
   DSC_0027.png

   (

   (

   (
   DSC_0033.png

   (

   (
   DSC_0026.JPG

   (
   DSC_0032.JPG

   (
   DSC_0036.png

   

   (
   DSC_0037.JPG

   (
DSC_0044
   DSC_0044.webp
   DSC_0045.JPG
   DSC_0059.png
   DSC_0059.webp
   DSC_0044.webp
DSC_0007
   DSC_0007.png
   DSC_0051.png
   DSC_0051.JPG
   DSC_0041.JPG
   DSC_0041.png
   DSC_0041.webp
   DSC_0058.png
   DSC_0058.JPG
   DSC_0058.webp
   DSC_0007.png
   DSC_0007.JPG
DSC_0007
   DSC_0007.JPG
   DSC_0055.JPG
   DSC_0055.png
DSC_0005
   DSC_0005.web
   DSC_0035.png
   DSC_0036.webp
   DSC_0005.webp
DSC_0053
   DSC_0053.web
   DSC_0034.JPG
   DSC_0048.JPG
   DSC_0048.png
   DSC_0048.webp
   DSC_0053.webp
DSC_0014
   DSC_0014.JPG
   DSC_0054.png
   DSC_0054.JPG
   DSC_0054.webp
   DSC_0034.webp
   DSC_0014.JPG
   DSC_0014.png
DSC_0014
   DSC_0014.png
   DSC_0053.png
   DSC_0049.png
   DSC_0049.JPG
DSC_0049
   DSC_0049.web
   DSC_0047.png
   DSC_0040.png
   DSC_0040.JPG
   DSC_0049.webp
DSC_0043
   DSC_0043.webp
   DSC_0042.JPG
   DSC_0042.png
   DSC_0042.webp
   DSC_0043.webp
DSC_0038
   DSC_0038.web
   DSC_0052.JPG
   DSC_0056.JPG
   DSC_0056.png
   DSC_0038.webp
   DSC_0038.png
   DSC_0038.JPG
DSC_0025
   DSC_0025.web
   DSC_0046.JPG
   DSC_0057.png
   DSC_0057.JPG
   DSC_0057.webp
   DSC_0025.webp
DSC_0005
   DSC_0005.png
   DSC_0044.png
   DSC_0043.png
   DSC_0043.JPG
   DSC_0005.JPG
   DSC_0005.png
DSC_0039
   DSC_0039.png
   DSC_0050.png
   DSC_0039.JPG
   DSC_0039.png
DSC_0038
   DSC_0038.png
DSC_0038
   DSC_0038.JPG
DSC_0048
   DSC_0048.webp
DSC_0006
   DSC_0006.JPG
   DSC_0006.JPG
   DSC_0006.png
DSC_0006
   DSC_0006.png
DSC_0032
   DSC_0032.webp
   DSC_0032.webp
DSC_0014
   DSC_0014.webp
DSC_0033
   DSC_0033.webp
DSC_0052
   DSC_0052.webp
DSC_0045
   DSC_0045.webp

Вот код:

const std = @import("std");
const fs = std.fs;
const path = std.fs.path;
const mem = std.mem;

const fileStruct = struct { baseName: []const u8, files: [][]const u8 };

pub fn main() !void {
    const args = try std.process.argsAlloc(std.heap.page_allocator);
    defer std.process.argsFree(std.heap.page_allocator, args);

    if (args.len < 2) {
        std.debug.print("Usage: {s} <directory>\n", .{args[0]});
        return;
    }

    const dir_path: []u8 = args[1];
    std.debug.print("Lets open the {s} directory\n", .{dir_path});

    // const allocator = std.heap.page_allocator;
    var target_dir = try fs.cwd().openDir(dir_path, .{});
    defer target_dir.close();

    var iter = target_dir.iterate();

    var groupedFiles = std.ArrayList(fileStruct).init(std.heap.page_allocator);

    while (try iter.next()) |entry| {
        // Ensure we only process files
        if (entry.kind != fs.Dir.Entry.Kind.file) continue;

        std.debug.print("File {s} ({})\n", .{ entry.name, entry.kind });

        var baseName = path.basename(entry.name);
        std.debug.print("Filename {s}\n", .{baseName});

        const extension = path.extension(baseName);

        if (extension.len != 0) {
            baseName = baseName[0 .. baseName.len - extension.len];
        }

        std.debug.print("Basename: {s}\n", .{baseName});

        var foundGroup: bool = false;

        for (groupedFiles.items) |*group| {
            if (mem.eql(u8, group.baseName, baseName)) {
                const new_files = try std.heap.page_allocator.alloc([]const u8, group.files.len + 1);
                for (group.files, 0..) |file, i| {
                    new_files[i] = file;
                }
                new_files[group.files.len] = try std.heap.page_allocator.dupe(u8, entry.name);
                group.files = new_files;
                foundGroup = true;
                break;
            }
        }

        if (!foundGroup) {
            const new_files = try std.heap.page_allocator.alloc([]const u8, 1);
            new_files[0] = entry.name;
            const newGroup = fileStruct{ .baseName = baseName, .files = new_files }; // Use & to coerce to slice
            try groupedFiles.append(newGroup);
        }
    }

    for (groupedFiles.items) |item| {
        std.debug.print("{s}\n", .{item.baseName});
        for (item.files) |file| {
            std.debug.print("   {s}\n", .{file});
        }
    }
}

Может кто-нибудь объяснить вывод? Если бы вы могли указать мне правильное направление для удаления больших файлов, это тоже было бы полезно, но сначала, что происходит?

В целом/с точки зрения структуры данных это выглядит так, как будто вы могли бы использовать хеш-карту. В частности, я думаю, что в вашем коде происходит утечка памяти, поскольку new_files выделяется и никогда не освобождается. Рассмотрите возможность использования std.heap.GeneralPurposeAllocator, который дает вам полезную обратную связь в отладочных сборках.

FObersteiner 20.07.2024 17:26
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
73
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Переменная entry действительна только для одной итерации. Это связано с тем, что итератор повторно использует одну и ту же память для каждой итерации. Но вы сохраняете указатели на entry.name в разделе if (!foundGroup):

new_files[0] = entry.name;
const newGroup = fileStruct{ .baseName = baseName, .files = new_files };

Вы можете исправить это, скопировав строки в выделенную память с помощью allocator.dupe:

new_files[0] = try std.heap.page_allocator.dupe(u8, entry.name);
const newGroup = fileStruct{
    .baseName = try std.heap.page_allocator.dupe(u8, baseName),
    .files = new_files
};

Это исправит вывод вашей программы.


Кроме того, как указано в комментариях, в конце вы не освобождаете память. Вы можете использовать GeneralPurposeAllocator, он поможет вам обнаружить утечку памяти:

var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer std.debug.assert(gpa.deinit() == .ok);
const allocator = gpa.allocator();

Чтобы освободить память сгруппированных файлов, вы можете сделать что-то вроде этого:

var groupedFiles = std.ArrayList(fileStruct).init(allocator);
defer {
    for (groupedFiles.items) |group| {
        for (group.files) |file| {
            allocator.free(file);
        }
        allocator.free(group.files);
        allocator.free(group.baseName);
    }
    groupedFiles.deinit();
}

Здесь вы также теряете память:

group.files = new_files;

Либо введите allocator.free(group.files) перед строкой, либо используйте realloc:

const new_files = try allocator.realloc(group.files, group.files.len + 1);
new_files[group.files.len] = try allocator.dupe(u8, entry.name);
group.files = new_files;
foundGroup = true;
break;

Я думаю, ваш первый пункт очень важен, я сначала упустил его значение. Похоже, это одна из «классических» ловушек, указывающих на временную память. Иногда мне трудно это заметить, поскольку в некоторых случаях это может сработать.

FObersteiner 21.07.2024 16:08

Для тех, кому интересно, вот ужасная реализация, которую я придумал после использования ответа @sigod.

Любые лучшие способы приветствуются.

const std = @import("std");
const fs = std.fs;
const path = std.fs.path;
const mem = std.mem;

const fileStruct = struct { baseName: []const u8, files: [][]const u8 };

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer std.debug.assert(gpa.deinit() == .ok);
    const allocator = gpa.allocator();
    const args = try std.process.argsAlloc(allocator);
    defer std.process.argsFree(allocator, args);

    if (args.len < 2) {
        std.debug.print("Usage: {s} <directory>\n", .{args[0]});
        return;
    }

    const dir_path: []const u8 = args[1];
    std.debug.print("Lets open the {s} directory\n", .{dir_path});

    // const allocator = allocator;
    var target_dir = try fs.cwd().openDir(dir_path, .{});
    defer target_dir.close();

    var iter = target_dir.iterate();

    var groupedFiles = std.ArrayList(fileStruct).init(allocator);
    defer {
        for (groupedFiles.items) |group| {
            for (group.files) |file| {
                allocator.free(file);
            }
            allocator.free(group.files);
            allocator.free(group.baseName);
        }
        groupedFiles.deinit();
    }

    while (try iter.next()) |entry| {
        // Ensure we only process files
        if (entry.kind != fs.Dir.Entry.Kind.file) continue;

        // std.debug.print("File {s} ({})\n", .{ entry.name, entry.kind });

        var baseName = path.basename(entry.name);

        if (mem.eql( u8, baseName, ".DS_Store")) continue;
        // std.debug.print("Filename {s}\n", .{baseName});

        const extension = path.extension(baseName);

        if (extension.len != 0) {
            baseName = baseName[0 .. baseName.len - extension.len];
        }

        // std.debug.print("Basename: {s}\n", .{baseName});

        var foundGroup: bool = false;

        for (groupedFiles.items) |*group| {
            if (mem.eql(u8, group.baseName, baseName)) {
                const new_files = try allocator.alloc([]const u8, group.files.len + 1);
                for (group.files, 0..) |file, i| {
                    new_files[i] = file;
                }
                new_files[group.files.len] = try allocator.dupe(u8, entry.name);
                allocator.free(group.files);
                group.files = new_files;
                foundGroup = true;
                break;
            }
        }

        if (!foundGroup) {
            const new_files = try allocator.alloc([]const u8, 1);
            new_files[0] = try allocator.dupe(u8, entry.name);
            const newGroup = fileStruct{ .baseName = try allocator.dupe(u8, baseName), .files = new_files };
            try groupedFiles.append(newGroup);
        }
    }

    for (groupedFiles.items) |item| {
        std.debug.print("{s} -> {s}\n", .{ item.baseName, item.files });
        if (item.files.len > 1) {
            var smallestSize: u64 = 0;
            var smallestIndex: usize = 0;

            for (item.files, 0..) |currentFile, idx| {
                const fullPath = try path.join(allocator, &[_][]const u8{ dir_path, currentFile });
                defer allocator.free(fullPath);
                var path_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
                const realPath = try fs.realpath(fullPath, &path_buffer);
                const file = try fs.openFileAbsolute(realPath, .{});
                defer file.close();
                const info = try file.stat();
                const size = info.size;
                std.debug.print("{any} -> {s}\n", .{ size, realPath });

                if (smallestSize == 0 or size < smallestSize) {
                    smallestSize = size;
                    smallestIndex = idx;
                }
            }

            std.debug.print("Smallest: {any} -> {any}\n", .{ smallestSize, smallestIndex });

            for (item.files, 0..) |file, idx| {
                if (idx != smallestIndex) {
                    const fullPath = try path.join(allocator, &[_][]const u8{ dir_path, file });
                    defer allocator.free(fullPath);
                    var path_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
                    const realPath = try fs.realpath(fullPath, &path_buffer);
                    try fs.deleteFileAbsolute(realPath);
                    std.debug.print("Deleted {s}\n", .{fullPath});
                }
            }
        }
    }
}

Другие вопросы по теме