Files
cKit/Foundation/c_FileIter.c
T
2026-08-29 01:50:50 +08:00

221 lines
6.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <c_FileIter.h>
#include <stdio.h>
#include <c_Memory.h>
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
#ifdef _WIN32
#include <windows.h>
typedef struct {
HANDLE hFind;
WIN32_FIND_DATAA findData;
} WinIterCtx;
#else
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
typedef struct {
DIR* dir;
} PosixIterCtx;
#endif
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
// 内部辅助函数:获取下一个有效条目(过滤 "." 和 ".."
static void c_FileIter_InternalFetch(c_FileIter_t* iter) {
#ifdef _WIN32
WinIterCtx* ctx = (WinIterCtx*)iter->internal_ctx;
while (FindNextFileA(ctx->hFind, &ctx->findData)) {
if (strcmp(ctx->findData.cFileName, ".") == 0 || strcmp(ctx->findData.cFileName, "..") == 0) {
continue; // 过滤
}
// 填充缓存
strncpy(iter->current.name, ctx->findData.cFileName, sizeof(iter->current.name) - 1);
iter->current.name[sizeof(iter->current.name) - 1] = '\0';
if (ctx->findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
iter->current.type = C_FILE_TYPE_DIR;
iter->current.size = 0;
} else {
iter->current.type = C_FILE_TYPE_REGULAR;
iter->current.size = ((unsigned long long)ctx->findData.nFileSizeHigh << 32) | ctx->findData.nFileSizeLow;
}
iter->has_next = C_TRUE;
return;
}
#else
PosixIterCtx* ctx = (PosixIterCtx*)iter->internal_ctx;
struct dirent* entry;
while ((entry = readdir(ctx->dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue; // 过滤
}
// 填充名字
strncpy(iter->current.name, entry->d_name, sizeof(iter->current.name) - 1);
iter->current.name[sizeof(iter->current.name) - 1] = '\0';
// 组装完整路径获取大文件大小及类型
char full_path[512];
snprintf(full_path, sizeof(full_path), "%s/%s", iter->base_path, entry->d_name);
struct stat stat_buf;
if (stat(full_path, &stat_buf) == 0) {
iter->current.size = (unsigned long long)stat_buf.st_size;
if (S_ISDIR(stat_buf.st_mode)) {
iter->current.type = C_FILE_TYPE_DIR;
} else if (S_ISREG(stat_buf.st_mode)) {
iter->current.type = C_FILE_TYPE_REGULAR;
} else {
iter->current.type = C_FILE_TYPE_UNKNOWN;
}
} else {
iter->current.type = C_FILE_TYPE_UNKNOWN;
iter->current.size = 0;
}
iter->has_next = C_TRUE;
return;
}
#endif
// 没有更多文件了,触发自动资源清理
iter->has_next = C_FALSE;
if (iter->internal_ctx) {
#ifdef _WIN32
FindClose(((WinIterCtx*)iter->internal_ctx)->hFind);
#else
closedir(((PosixIterCtx*)iter->internal_ctx)->dir);
#endif
C_FREE(iter->internal_ctx);
iter->internal_ctx = NULL;
}
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
c_err_t c_FileIter_Init(c_FileIter_t* iter, const char* dirpath) {
if (!iter || !dirpath) return C_ERR_FAIL;
iter->internal_ctx = NULL;
iter->has_next = C_FALSE;
strncpy(iter->base_path, dirpath, sizeof(iter->base_path) - 1);
iter->base_path[sizeof(iter->base_path) - 1] = '\0';
#ifdef _WIN32
WinIterCtx* ctx = (WinIterCtx*)C_ALLOC(sizeof(WinIterCtx));
if (!ctx) return C_ERR_FAIL;
char search_path[512];
snprintf(search_path, sizeof(search_path), "%s\\*", dirpath);
ctx->hFind = FindFirstFile(search_path, &ctx->findData);
if (ctx->hFind == INVALID_HANDLE_VALUE) {
C_FREE(ctx);
return C_ERR_FAIL;
}
iter->internal_ctx = ctx;
// 检查第一个读取到的是否是 "." 或 "..",如果是,则继续查找有效文件
if (strcmp(ctx->findData.cFileName, ".") == 0 || strcmp(ctx->findData.cFileName, "..") == 0) {
c_FileIter_InternalFetch(iter);
} else {
strncpy(iter->current.name, ctx->findData.cFileName, sizeof(iter->current.name) - 1);
iter->current.name[sizeof(iter->current.name) - 1] = '\0';
if (ctx->findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
iter->current.type = C_FILE_TYPE_DIR;
iter->current.size = 0;
} else {
iter->current.type = C_FILE_TYPE_REGULAR;
iter->current.size = ((unsigned long long)ctx->findData.nFileSizeHigh << 32) | ctx->findData.nFileSizeLow;
}
iter->has_next = C_TRUE;
}
#else
PosixIterCtx* ctx = (PosixIterCtx*)C_ALLOC(sizeof(PosixIterCtx));
if (!ctx) return C_ERR_FAIL;
ctx->dir = opendir(dirpath);
if (!ctx->dir) {
C_FREE(ctx);
return C_ERR_FAIL;
}
iter->internal_ctx = ctx;
// 触发预读第一项
c_FileIter_InternalFetch(iter);
#endif
return C_ERR_OK;
}
c_bool_t c_FileIter_HasNext(c_FileIter_t* iter) {
return (iter != NULL) ? iter->has_next : C_FALSE;
}
void c_FileIter_Next(c_FileIter_t* iter) {
if (iter && iter->has_next) {
c_FileIter_InternalFetch(iter);
}
}
const c_FileEntry_t* c_FileIter_Get(c_FileIter_t* iter) {
if (iter && iter->has_next) {
return &(iter->current);
}
return NULL;
}
c_err_t c_FileIter_Remove(c_FileIter_t* iter) {
if (!iter || !iter->has_next) return C_ERR_FAIL;
char full_path[512];
#ifdef _WIN32
snprintf(full_path, sizeof(full_path), "%s\\%s", iter->base_path, iter->current.name);
#else
snprintf(full_path, sizeof(full_path), "%s/%s", iter->base_path, iter->current.name);
#endif
int res = -1;
if (iter->current.type == C_FILE_TYPE_DIR) {
#ifdef _WIN32
res = RemoveDirectory(full_path) ? 0 : -1;
#else
res = rmdir(full_path);
#endif
} else {
#ifdef _WIN32
res = DeleteFile(full_path) ? 0 : -1;
#else
res = unlink(full_path);
#endif
}
// 执行完物理删除后,提前释放当前迭代器的内部流句柄,防止调用者后续发生未知异常
iter->has_next = C_FALSE;
if (iter->internal_ctx) {
#ifdef _WIN32
FindClose(((WinIterCtx*)iter->internal_ctx)->hFind);
#else
closedir(((PosixIterCtx*)iter->internal_ctx)->dir);
#endif
C_FREE(iter->internal_ctx);
iter->internal_ctx = NULL;
}
return (res == 0) ? C_ERR_OK : C_ERR_FAIL;
}