Skip to content

Instantly share code, notes, and snippets.

@leozzyzheng
Created March 12, 2017 07:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leozzyzheng/7174db44c60f43cdfe7ba0c72b357297 to your computer and use it in GitHub Desktop.
Save leozzyzheng/7174db44c60f43cdfe7ba0c72b357297 to your computer and use it in GitHub Desktop.
List directory in win32
#include <assert.h>
#include <iostream>
#include <stack>
#include <string>
#include <windows.h>
class DirInfo {
public:
DirInfo(const wchar_t* dir_path) {
path = CleanPath(dir_path);
return_dot_and_dotdot = true;
list_into_dir_flag = true;
}
~DirInfo() {
ResetList();
}
static std::wstring CleanPath(const std::wstring& path) {
if (path.empty()) {
return L"";
}
std::wstring copy = path;
size_t offset = 0;
while ((offset = copy.find_first_of(L'\\', offset)) != std::wstring::npos) {
copy.replace(offset, 1, L"/");
}
if (copy.find_last_of(L'/') == copy.size() - 1) {
copy.resize(copy.size() - 1);
}
return std::move(copy);
}
bool IsValid() const {
auto attr = ::GetFileAttributesW(path.c_str());
if (attr != INVALID_FILE_ATTRIBUTES) {
if (attr && FILE_ATTRIBUTE_DIRECTORY) {
return true;
}
}
return false;
}
void SetListRetrunDotAndDotDot(bool will_return) {
return_dot_and_dotdot = will_return;
}
bool ListFiles(WIN32_FIND_DATAW* file_data, std::wstring* full_path) {
if (file_data == NULL) {
assert(file_data != NULL);
return false;
}
HANDLE file_handle;
if (list_into_dir_flag) {
list_into_dir_flag = false;
std::wstring dir;
if (dir_stack.empty()) {
dir = path;
} else {
dir = dir_stack.top();
}
file_handle = ::FindFirstFileW((dir + L"/*").c_str(), file_data);
if (file_handle == INVALID_HANDLE_VALUE) {
return false;
}
if (dir_stack.empty()) {
handle_stack.push(file_handle);
dir_stack.push(path);
} else {
assert(handle_stack.top() == INVALID_HANDLE_VALUE);
handle_stack.pop();
handle_stack.push(file_handle);
}
} else {
if (handle_stack.empty()) {
return false;
}
file_handle = handle_stack.top();
while (::FindNextFileW(file_handle, file_data) == FALSE) {
::FindClose(file_handle);
handle_stack.pop();
dir_stack.pop();
if (handle_stack.empty()) {
return false;
}
file_handle = handle_stack.top();
}
}
auto is_dot_or_dotdot = wcscmp(file_data->cFileName, L".") == 0 ||
wcscmp(file_data->cFileName, L"..") == 0;
if (is_dot_or_dotdot && !return_dot_and_dotdot) {
return ListFiles(file_data, full_path);
}
std::wstring file_full_path = dir_stack.top() + L"/" + file_data->cFileName;
if (!is_dot_or_dotdot && file_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
handle_stack.push(INVALID_HANDLE_VALUE);
dir_stack.push(file_full_path);
list_into_dir_flag = true;
}
if (full_path != NULL) {
*full_path = std::move(file_full_path);
}
return true;
}
void ResetList() {
list_into_dir_flag = true;
while (!handle_stack.empty()) {
auto handle = handle_stack.top();
if (handle != INVALID_HANDLE_VALUE) {
::FindClose(handle);
}
handle_stack.pop();
}
while (!dir_stack.empty()) {
dir_stack.pop();
}
}
private:
std::wstring path;
bool return_dot_and_dotdot;
bool list_into_dir_flag;
std::stack<HANDLE> handle_stack;
std::stack<std::wstring> dir_stack;
};
int main() {
std::wstring cmd;
LPWSTR *szArgList;
int argCount;
szArgList = CommandLineToArgvW(GetCommandLine(), &argCount);
if (szArgList != NULL && argCount > 1) {
cmd = szArgList[1];
}
DirInfo dir(cmd.c_str());
dir.SetListRetrunDotAndDotDot(false);
WIN32_FIND_DATAW file_data = { 0 };
std::wstring full_path;
int file_count = 0;
int dir_count = 0;
while (dir.ListFiles(&file_data, &full_path)) {
std::wcout << full_path;
if (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
std::cout << " is directory" << std::endl;
++dir_count;
} else {
std::cout << " is file" << std::endl;
++file_count;
}
}
std::cout << "total:" << dir_count << "directories," << file_count << "files" << std::endl;
system("pause");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment