如何用Boost.Filesystem按文件大小降序排序并输出前5大文件
Hey there! Let's get your code sorted (pun intended) so you can list the top 5 largest files in a directory. The core issue right now is that you're only storing filenames in your vector—you need to track file sizes (and other metadata) alongside the names to sort properly. Here's a step-by-step fix:
Step 1: Create a Struct to Hold File Metadata
First, define a struct to store all the info you need for each file. This keeps related data together and makes sorting straightforward:
struct FileInfo { std::string filename; uintmax_t size; boost::filesystem::path full_path; time_t last_write; DWORD attributes; };
Step 2: Populate the Struct with File Data
Instead of storing just filenames, fill this struct with all relevant data as you iterate through the directory. This fixes the bug where you were using the directory's last write time instead of the file's, and uses Boost's path handling for safer path construction.
Step 3: Sort by File Size (Descending)
Use a custom comparator (or lambda) to sort the vector<FileInfo> so the largest files come first.
Step 4: Output the Top 5 Files
After sorting, loop through the first 5 elements (or fewer if there aren't 5 files) to display your results.
Modified Complete Code
Here's the updated code with all these changes:
#define _CRT_SECURE_NO_WARNINGS #include <Windows.h> #include <iostream> #include <vector> #include <algorithm> #include <string> #include <boost/filesystem.hpp> using namespace std; using namespace boost::filesystem; struct FileInfo { std::string filename; uintmax_t size; boost::filesystem::path full_path; time_t last_write; DWORD attributes; }; void ShowAttributes(DWORD attributes); void AttribFile(const char* str); void Attrib(); // Helper to check if file is executable (add your actual logic here if needed) bool Is_Executable_File(const path& p) { string ext = p.extension().string(); return (ext == ".exe" || ext == ".com" || ext == ".bat"); } int main(int argc, char* argv[]) { SetConsoleCP(1251); SetConsoleOutputCP(1251); if (argc < 2) { cout << "Usage: " << argv[0] << " <directory path>" << endl; return 1; } path dir_path(argv[1]); try { if (exists(dir_path)) { if (is_regular_file(dir_path)) { // Handle single file case cout << dir_path << " Size " << file_size(dir_path) << " bytes "; time_t Time = last_write_time(dir_path); cout << asctime(localtime(&Time)) << endl; AttribFile(dir_path.c_str()); } else if (is_directory(dir_path)) { cout << "Directory " << dir_path << " - Top 5 largest files:" << endl; vector<FileInfo> file_list; // Iterate through directory and populate FileInfo structs for (const auto& entry : directory_iterator(dir_path)) { if (is_regular_file(entry.path())) { FileInfo info; info.filename = entry.path().filename().string(); info.full_path = entry.path(); info.size = file_size(entry.path()); info.last_write = last_write_time(entry.path()); info.attributes = GetFileAttributesA(entry.path().c_str()); file_list.push_back(info); } } // Sort files by size in descending order sort(file_list.begin(), file_list.end(), [](const FileInfo& a, const FileInfo& b) { return a.size > b.size; }); // Output top 5 files int count = 0; for (const auto& file : file_list) { if (count >= 5) break; cout << " " << file.filename; if (Is_Executable_File(file.full_path)) cout << "*"; cout << " Size " << file.size << " bytes "; cout << asctime(localtime(&file.last_write)); ShowAttributes(file.attributes); cout << endl; count++; } if (file_list.empty()) { cout << " No regular files found in this directory." << endl; } } } else { cout << dir_path << " does not exist!" << endl; } } catch (const filesystem_error& ex) { cout << "Error: " << ex.what() << endl; } return 0; } void ShowAttributes(DWORD attributes) { if (attributes & FILE_ATTRIBUTE_ARCHIVE) cout << " archive"; if (attributes & FILE_ATTRIBUTE_DIRECTORY) cout << " directory"; if (attributes & FILE_ATTRIBUTE_HIDDEN) cout << " hidden"; if (attributes & FILE_ATTRIBUTE_NORMAL) cout << " normal"; if (attributes & FILE_ATTRIBUTE_READONLY) cout << " read only"; if (attributes & FILE_ATTRIBUTE_SYSTEM) cout << " system"; if (attributes & FILE_ATTRIBUTE_TEMPORARY) cout << " temporary"; } void AttribFile(const char* str) { DWORD attributes = GetFileAttributesA(str); ShowAttributes(attributes); } void Attrib() { char filename[MAX_PATH]; DWORD attributes; cout << "Name of file: "; cin >> filename; attributes = GetFileAttributesA(filename); ShowAttributes(attributes); }
Key Changes Explained:
- Struct
FileInfo: Stores all necessary file metadata in one place, making sorting and data access intuitive. - Path Handling: Uses Boost's native path concatenation instead of manual string building to avoid cross-platform path separator issues.
- Correct Timestamp: Now fetches the file's own last write time instead of the directory's.
- Custom Sort Lambda: The inline lambda function in
sort()compares file sizes and orders them from largest to smallest. - Top 5 Logic: Loops through the sorted list and stops after 5 entries, with a check for empty directories.
- Executable Check: Added a basic implementation for
Is_Executable_File(replace with your actual logic if you have more specific checks).
内容的提问来源于stack exchange,提问作者Кирилл Тихонов

