Foundations
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user