如何在不使用dirent.h或Boost的情况下从零实现目录文件列表(课程项目)
Alright, let's tackle this head-on—your instructor's no-nonsense rule about ditching dirent.h/Boost means we have to get creative with the only tools we have: those accessibility-checking functions you mentioned. Here's a complete, compliant solution that builds everything from scratch.
Core Idea
Since we can't use system directory traversal APIs, we'll rely on brute-force enumeration + validation. On Windows (given the LPCSTR mention), all files have a compatible 8.3 short filename, so we can generate every possible valid short filename, then use your provided functions to check if it exists as a file (not a directory) in the target folder.
Header File (DirFileFetcher.h)
First, the header with clean declarations—we'll keep it minimal per best practices:
#ifndef DIR_FILE_FETCHER_H #define DIR_FILE_FETCHER_H #include <stddef.h> #include <stdbool.h> // Replace these with your actual function prototypes (match what you were given) bool DoDirectoryExists(LPCSTR dirPath); bool DoFileExists(LPCSTR filePath); /** * Fetches all filenames in a specified directory * @param dirPath Target directory (MUST end with a backslash, e.g., "C:\\MyFiles\\") * @param fileNames Pre-allocated array of char* to store filenames * @param maxCount Maximum number of filenames the array can hold * @return Number of filenames found; returns 0 on invalid input or empty directory */ size_t GetDirectoryFiles(LPCSTR dirPath, char** fileNames, size_t maxCount); #endif // DIR_FILE_FETCHER_H
Implementation (DirFileFetcher.c)
This is where the magic happens—we'll generate all possible 8.3 filenames and validate each one:
#include "DirFileFetcher.h" #include <string.h> #include <stdlib.h> // Valid characters for 8.3 filenames (covers all standard Windows filename chars) static const char* const VALID_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"; static const size_t CHAR_COUNT = strlen(VALID_CHARS); // Helper: Generates a string from an index (for brute-force combinations) static void generate_string(char* out, size_t length, unsigned long long index) { memset(out, 0, length + 1); for (size_t i = 0; i < length; i++) { out[length - 1 - i] = VALID_CHARS[index % CHAR_COUNT]; index /= CHAR_COUNT; } } size_t GetDirectoryFiles(LPCSTR dirPath, char** fileNames, size_t maxCount) { // Sanity checks first if (!dirPath || !fileNames || maxCount == 0 || !DoDirectoryExists(dirPath)) { return 0; } size_t found = 0; char full_path[260]; // MAX_PATH on Windows is 260, safe default size_t dir_len = strlen(dirPath); // Enumerate all possible 8.3 filenames: 1-8 chars for name, 0-3 for extension for (size_t name_len = 1; name_len <= 8 && found < maxCount; name_len++) { unsigned long long name_combinations = 1; for (size_t i = 0; i < name_len; i++) name_combinations *= CHAR_COUNT; for (unsigned long long name_idx = 0; name_idx < name_combinations && found < maxCount; name_idx++) { char name[9] = {0}; generate_string(name, name_len, name_idx); // Check files with no extension first snprintf(full_path, sizeof(full_path), "%s%s", dirPath, name); if (DoFileExists(full_path) && !DoDirectoryExists(full_path)) { fileNames[found] = malloc(strlen(name) + 1); if (fileNames[found]) { strcpy(fileNames[found], name); found++; } } // Now check files with extensions (1-3 chars) for (size_t ext_len = 1; ext_len <= 3 && found < maxCount; ext_len++) { unsigned long long ext_combinations = 1; for (size_t i = 0; i < ext_len; i++) ext_combinations *= CHAR_COUNT; for (unsigned long long ext_idx = 0; ext_idx < ext_combinations && found < maxCount; ext_idx++) { char ext[4] = {0}; generate_string(ext, ext_len, ext_idx); snprintf(full_path, sizeof(full_path), "%s%s.%s", dirPath, name, ext); if (DoFileExists(full_path) && !DoDirectoryExists(full_path)) { size_t filename_len = strlen(name) + 1 + strlen(ext); // +1 for the dot fileNames[found] = malloc(filename_len + 1); if (fileNames[found]) { sprintf(fileNames[found], "%s.%s", name, ext); found++; } } } } } } return found; }
Critical Notes for Your Project
- Path Format: Make sure the input directory path ends with a backslash (
\). If you forget this, the filename will be appended directly to the directory name (e.g.,C:\Testfile.txtinstead ofC:\Test\file.txt), which will fail validation. - Memory Management: The caller is responsible for freeing each
char*in thefileNamesarray after use—don't forget to add this to your usage example to show you understand memory safety. - Performance Tradeoff: Brute-force enumeration is slow, but it's the only way to do this without using directory-specific libraries. Be sure to mention this in your project documentation to demonstrate you recognize the limitation.
- Long Filenames: This implementation relies on 8.3 short filenames, which Windows automatically generates for all files. So even if a file has a long name, its short name will be found here.
Usage Example
Show your instructor you know how to use the header properly:
#include <stdio.h> #include "DirFileFetcher.h" int main() { char* file_list[50]; // Allocate space for up to 50 filenames size_t file_count = GetDirectoryFiles("C:\\MyProject\\", file_list, 50); printf("Found %zu files:\n", file_count); for (size_t i = 0; i < file_count; i++) { printf(" - %s\n", file_list[i]); free(file_list[i]); // Clean up memory! } return 0; }
内容的提问来源于stack exchange,提问作者Cain Wildtale

