Skip to content

THEMIScale/GhosttyBooRecreation

Repository files navigation

ConvertFile.bak 程序说明

概述

该程序用于读取指定目录 TXT_DIR 下的 .txt 文件名,并按照文件名中的数字顺序排序后打印。实现风格采用 C 语言方式:

  • 使用 char*char**
  • 使用 malloc / realloc / free
  • 使用 qsort 排序
  • 使用 POSIX 目录读取接口 opendir / readdir / closedir

运行方式

cd /home/kali/TermVedioPlayer/PlayerOnTerm
g++ ConvertFile.cpp -o ConvertFile -std=c++17 -O2 -Wall
./ConvertFile

注意:程序当前假设 TXT_DIR../b025fe84-7fa2-4ad3-95e6-f3348fc00a1b,并且目录内含 .txt 文件。

执行流程图

flowchart TD
    A[main()] --> B[GetAllFileNames(TXT_DIR, &names, &n)]
    B --> C{read directory entries}
    C -->|skip . / ..| C
    C -->|is directory| B
    C -->|is file| D[IsTxtFile(entry->d_name)]
    D -->|yes| E[copy relative path to malloc buffer]
    E --> F[realloc names array]
    F --> G[append file path]
    C -->|no| C
    B --> H[qsort(names, n, sizeof(char*), CompareByFrameNumber)]
    H --> I[print sorted names]
    I --> J[FreeNames(names, n)]
    J --> K[exit]
Loading

主要函数说明

main()

int main() {
    char **names = NULL;
    int n = 0;

    if (GetAllFileNames(TXT_DIR, &names, &n) != 0) {
        fprintf(stderr, "error opening dir: %s\n", TXT_DIR);
        return 1;
    }

    printf("total %d files\n", n);
    qsort(names, n, sizeof(char *), CompareByFrameNumber);
    for (int i = 0; i < n; i++) {
        printf("%s\n", names[i]);
    }

    FreeNames(names, n);
    return 0;
}

main() 做了什么

  • 初始化 namesNULLn 为文件数量计数。
  • 调用 GetAllFileNames 收集目标目录下符合条件的文件名。
  • 调用 qsortnames 数组进行排序。
  • 遍历排序结果并打印每个文件名。
  • 释放 names 数组和每个字符串占用的内存。

为什么这么实现

  • char **names 适合保存 C 风格字符串数组,并与 qsort 兼容。
  • 把目录查找和排序逻辑分离,提高程序结构清晰度。
  • 统一释放内存,避免资源泄漏。

GetAllFileNames()

int GetAllFileNames(const char *dirpath, char ***names, int *count) {
    DIR *dir = opendir(dirpath);
    if (dir == NULL) {
        return -1;
    }

    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 ||
            strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        char full_path[4096];
        snprintf(full_path, sizeof(full_path), "%s/%s", dirpath, entry->d_name);

        struct stat stat_buf;
        if (stat(full_path, &stat_buf) == -1) {
            continue;
        }

        if (S_ISDIR(stat_buf.st_mode)) {
            GetAllFileNames(full_path, names, count);
        } else {
            if (!IsTxtFile(entry->d_name)) {
                continue;
            }

            const char *relative = full_path + strlen(TXT_DIR);
            char *copy = (char *)malloc(strlen(relative) + 1);
            if (copy == NULL) {
                closedir(dir);
                return -1;
            }
            strcpy(copy, relative);

            char **tmp =
                (char **)realloc(*names, (*count + 1) * sizeof(char *));
            if (tmp == NULL) {
                free(copy);
                closedir(dir);
                return -1;
            }
            *names = tmp;
            (*names)[*count] = copy;
            (*count)++;
        }
    }

    closedir(dir);
    return 0;
}

GetAllFileNames() 做了什么

  • 打开目录 dirpath
  • 逐项读取目录内容。
  • 跳过特殊目录 ...
  • 通过 stat 判断目录项类型。
  • 如果是目录,则递归进入子目录。
  • 如果是普通文件且扩展名为 .txt,则把相对路径复制到内存中,并追加到 names 数组。

为什么这么实现

  • opendir / readdir / closedir 是 POSIX 目录遍历标准,适用于 UNIX/Linux。
  • 递归处理目录可支持多层目录结构。
  • 通过 realloc 动态扩容数组,避免预先估算文件数量。
  • 使用独立的 malloc 复制缓冲区,确保每个文件名都可单独释放。

IsTxtFile()

int IsTxtFile(const char *name) {
    size_t len = strlen(name);
    return len > 4 && strcmp(name + len - 4, ".txt") == 0;
}

IsTxtFile() 做了什么

  • 判断文件名长度是否大于 4。
  • 比较最后 4 个字符是否为 .txt

为什么这么实现

  • 简单直接地判断后缀,避免复杂的字符串处理。
  • 适用于文件名后缀固定的情况。

FreeNames()

void FreeNames(char **names, int count) {
    for (int i = 0; i < count; i++) {
        free(names[i]);
    }
    free(names);
}

FreeNames() 做了什么

  • 逐个释放 names 数组中保存的每个字符串内存。
  • 最后释放 names 数组本身。

为什么这么实现

  • 每个字符串由 malloc 分配,必须逐个释放。
  • names 数组本身由 reallocmalloc 分配,也必须释放。
  • 这是标准 C 内存管理方式。

CompareByFrameNumber()

int CompareByFrameNumber(const void *a, const void *b) {
    const char *const *pa = (const char *const *)a;
    const char *const *pb = (const char *const *)b;
    const char *sa = *pa;
    const char *sb = *pb;

    const char *dotA = strrchr(sa, '.');
    const char *dotB = strrchr(sb, '.');
    if (dotA == NULL || dotB == NULL || dotA - sa < 4 || dotB - sb < 4) {
        return strcmp(sa, sb);
    }

    char bufA[5] = {0};
    char bufB[5] = {0};
    memcpy(bufA, dotA - 4, 4);
    memcpy(bufB, dotB - 4, 4);
    int numA = atoi(bufA);
    int numB = atoi(bufB);
    if (numA < numB)
        return -1;
    if (numA > numB)
        return 1;
    return strcmp(sa, sb);
}

CompareByFrameNumber() 做了什么

  • qsort 传入的 void * 指针转换为 const char *const *
  • 提取两个文件名中最后一个 . 的位置。
  • 如果文件名没有后缀或格式异常,使用普通字符串比较返回结果。
  • 否则取 . 前 4 个字符作为数字部分,转换为整数进行比较。
  • 如果数字相同,则回退到字符串比较。

为什么这么实现

  • qsort 回调必须符合 int (*)(const void *, const void *)
  • 通过指针解引用实现对 char* 元素的比较。
  • 按文件名中的数字排序,更符合 frame_0001.txt 类型文件的排序需求。
  • 次级比较保留稳定排序行为。

附录

本程序设计思想:

  • 使用 C 风格内存和字符串处理,减少 C++ 特性依赖。
  • 使用 qsortCompareByFrameNumber 完成自定义排序。
  • 使用递归目录遍历支持子目录查找。
  • 使用显式内存管理保证运行后不会泄漏。

About

this is a recreation of "ghostty +boo"

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors