My goal is to only use built in methods of C++/Windows (I don't think std::filesystem is supported on my version of C++) to get the filenames within a folder.
right now I have this:
HANDLE hFind;
WIN32_FIND_DATA data;
hFind = FindFirstFile("C:\\Folder\\*", &data);
if (hFind != INVALID_HANDLE_VALUE) {
do {
//Process File Name
std::wstring ws(data.cFileName);
} while (FindNextFile(hFind, &data));
FindClose(hFind);
}
Which seems to be returning blank names and not the names of the files in the folder.
Am I using this FindFirstFile function correctly? Is there a better way to do this?
Your code can't compile as shown. You are calling the ANSI version of FindFirstFile() (by virtue of you passing it a narrow ANSI string literal instead of a wide Unicode string literal), and std::wstring does not have a constructor that accepts a char[] as input.
Baring that mistake, you are also ignoring the data.dwFileAttributes field to distinguish between files and subfolders, and in the case of subfolders you are not checking the contents of data.cFileName to ignore the "." and ".." special folder names.
Try this:
WIN32_FIND_DATAW data;
HANDLE hFind = FindFirstFileW(L"C:\\Folder\\*", &data);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
{
// Process File Name
std::wstring ws(data.cFileName);
...
}
else
{
if ((lstrcmpW(data.cFileName, L".") != 0) &&
(lstrcmpW(data.cFileName, L"..") != 0))
{
// Process Folder Name
std::wstring ws(data.cFileName);
...
}
}
}
while (FindNextFileW(hFind, &data));
FindClose(hFind);
}
Related
I'm trying to find list of files in a directory programmatically and I've written the following code
CStringArray CCL2ProjectDirectoryPage::GetAllFilesNames()
{
WIN32_FIND_DATA fileData;
memset(&fileData, 0, sizeof(WIN32_FIND_DATA));
HANDLE handle = FindFirstFile("d:\\test\\*", &fileData);
CStringArray strArray;
while(handle != INVALID_HANDLE_VALUE)
{
strArray.Add(fileData.cFileName); // the problem is that the fileData.cFileName always contains "."
if(FALSE == FindNextFile(handle, &fileData))
break;
}
FindClose(handle);
return strArray;
}
The problem is that the fileData.cFileName always contains ".".
"." with the first file, ".." with the second file and so on.
what is wrong with this code?
Thanks in advance.
Your code uses just Win32 API to traverse directory/folder. The MFC way of doing this is much simpler. The framework comes with CFileFind which is much easier to use. Also you can not return CStringArray as it does not have copy constructor. You should be using CStringArray reference as out param of your method
void CCL2ProjectDirectoryPage::GetAllFilesNames(CStringArray& files)
{
CFileFind finder;
// start working for files
BOOL bWorking = finder.FindFile(_T("d:\\test\\*"));
while (bWorking)
{
bWorking = finder.FindNextFile();
// skip . and .. files
if (!finder.IsDots())
{
files.Add(finder.GetFileName());
}
}
}
You want this:
CStringArray GetAllFilesNames()
{
WIN32_FIND_DATA fileData;
memset(&fileData, 0, sizeof(WIN32_FIND_DATA));
HANDLE handle = FindFirstFile("d:\\test\\*", &fileData);
CStringArray strArray;
if (handle != INVALID_HANDLE_VALUE)
{
do
{
if (_tcscmp(fileData.cFileName, _T(".")) != 0 && // ignore "." and ".."
_tcscmp(fileData.cFileName, _T("..")) != 0)
{
strArray.Add(fileData.cFileName);
}
} while (FindNextFile(handle, &fileData));
FindClose(handle);
}
return strArray;
}
Disclaimer: this is untested and minimal error checking code just for demonstration purposes.
I'm writing an app in Qt and trying to use the windows functions FindFirstFile and FindNextFile in order to speed up counting large numbers of files in several directories. I've copied this code almost verbatum off the microsoft site in order to list files, but debugging it shows that it's only listing one file when I trigger the function;
QStringList Manager::returnDirectoryFileData(QString ChangedDirectory)
{
QStringList DirectoryFiles;
WIN32_FIND_DATA FindFileData;
LARGE_INTEGER filesize;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError = 0;
//string directorySearch = "E:\\My Documents\\Visual Studio 2010\\Projects\\SEP-Asignment-One\\Debug\\*";
// Find the first file in the directory.
LPCWSTR ConvertedDir = (const wchar_t*)ChangedDirectory.utf16();
PVOID OldValue = NULL;
if (Wow64DisableWow64FsRedirection(&OldValue))
{
hFind = FindFirstFile(ConvertedDir, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
printf("Invalid file handle. Error is %u.\n", GetLastError());
}
do
{
QString Newname = "Want to do stuff here";
DirectoryFiles.append(Newname);
printf(" %s <DIR>\n", FindFileData.cFileName);
} while (FindNextFile(hFind, &FindFileData) != 0);
dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
DisplayErrorBox(TEXT("FindFirstFile"));
}
FindClose(hFind);
}
Wow64RevertWow64FsRedirection(&OldValue);
return DirectoryFiles;
}
This is a 32 bit program running on 64 bit windows 10, so the Wow64DisableWow64fsredirection is supposed to be called before these functions are used. Anyone know what I'm doing wrong? Thanks!
My aim is to list the textfiles in a specific directory and let the user load one of the files.
I'm using Windows, Unicode is predefined in my compiler.
Question: FileHandle has always INVALID_HANDLE_VALUE. What's the cause of this and how can I correct it?
My last code looks like this:
ListAllTxtFiles(L"C:\\Users\\Tnc\Desktop\\Yazılım Çalışmaları\\Projects\\Oyun Projem\\data\\SaveFiles\\");
void ListAllTxtFiles(const wchar_t *Directory)
{
TCHAR Buffer[2048];
wsprintf(Buffer, L"s%*.txt", Directory);//there are security considerations about this function
WIN32_FIND_DATAW FindData;
HANDLE FileHandle = FindFirstFileW(Buffer, &FindData);
if (FileHandle == INVALID_HANDLE_VALUE)
{
printf("Could not find any files..\n");
}
else
{
do
{
printf("Found %s\\%s\n", Directory, FindData.cFileName);
} while (FindNextFile(FileHandle, &FindData));
CloseHandle(FileHandle);
}
}
wsprintf(Buffer, L"s%*.txt", Directory);
should be
wsprintf(Buffer, L"%s*.txt", Directory);
You just got your wsprintf format string wrong.
My question crossreferrer with [question]Visual C#: Move multiple files with the same extensions into another directory
but i have yet biggest problem - my directory contain more than 3 million files. C# with .GetFiles() can not solve my problem.
I think, that only with C++ i can do it.
Algorithm
CreateDir "temp"+counterDirs
FindFirst file into source dir
MoveFile into newDir (created on step 1)
increment counterFiles
repeat Steps 2-4 until FindFirst not have error(stop prog) or counterFiles < moveLimit (exmpl 100 000)
increment counterDirs
repeat all from Steps 1-6
target: move all files from src-dir (3 million) into a few target-dirs with 100 000 files.
Please help me with coding - i don't know C++ (VS 2010)
This is my code
`int _tmain(int argc, TCHAR *argv[])
{
WIN32_FIND_DATA ffd;
LARGE_INTEGER filesize;
TCHAR szDir[MAX_PATH];
TCHAR szNewDir[MAX_PATH];
TCHAR szNewDirEx[MAX_PATH];
size_t length_of_arg;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError=0;
DWORD dwFiles = 0;
DWORD dwDirs = 0;
// If the directory is not specified as a command-line argument,
// print usage.
if(argc != 2)
{
_tprintf(TEXT("\nUsage: %s <directory name>\n"), argv[0]);
return (-1);
}
// Check that the input path plus 3 is not longer than MAX_PATH.
// Three characters are for the "\*" plus NULL appended below.
StringCchLength(argv[1], MAX_PATH, &length_of_arg);
if (length_of_arg > (MAX_PATH - 3))
{
_tprintf(TEXT("\nDirectory path is too long.\n"));
return (-1);
}
_tprintf(TEXT("\nTarget directory is %s\n\n"), argv[1]);
// Prepare string for use with FindFile functions. First, copy the
// string to a buffer, then append '\*' to the directory name.
StringCchCopy(szDir, MAX_PATH, argv[1]);
StringCchCat(szDir, MAX_PATH, TEXT("\\*"));
StringCchCopy(szNewDir, MAX_PATH, argv[1]);
StringCchCat(szNewDir, MAX_PATH, TEXT("\\dir"));
StringCchCat(szNewDirEx, MAX_PATH, szNewDir);
// Find the first file in the directory.
hFind = FindFirstFile(szDir , &ffd);
if (INVALID_HANDLE_VALUE == hFind)
{
DisplayErrorBox(TEXT("FindFirstFile"));
return dwError;
}
// List all the files in the directory with some info about them.
do
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
_tprintf(TEXT(" %s <DIR>\n"), ffd.cFileName);
}
else
{
if(dwFiles == 0) {
StringCchCat(szNewDirEx, MAX_PATH, TEXT(dwDirs));
CreateDir(szNewDirEx); //dwDirs toString
}
if (!MoveFileEx(__OLDDIR__ + ffd.cFileName, szNewDirEx + ffd.cFileName, MOVEFILE_WRITE_THROUGH))
{
printf ("MoveFileEx failed with error %d\n", GetLastError());
return;
} else {
dwFiles++;
if (dwFiles == 50000) {
dwDirs++;
dwFiles = 0;
}
}
}
}
while (FindFirstFile(hFind, &ffd) != 0);
dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
DisplayErrorBox(TEXT("FindFirstFile"));
}
FindClose(hFind);
return dwError;
}
I found solution my task in How to use DirectoryInfo.GetFiles and have it stop after finding the first match?. I will try run this in my directory and will post result later.
Complete. Code in thread link worked perfect.
How to get list of folders in this folder?
FindFirstFileEx+FindExSearchLimitToDirectories.
WIN32_FIND_DATA fi;
HANDLE h = FindFirstFileEx(
dir,
FindExInfoStandard,
&fi,
FindExSearchLimitToDirectories,
NULL,
0);
if (h != INVALID_HANDLE_VALUE) {
do {
if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
printf("%s\n", fi.cFileName);
} while (FindNextFile(h, &fi));
FindClose(h);
}
If you can't use .NET & Managed code, you can go through the win32 api's
Here is an example that you can modify to only get Folders.
(Basically the following check:)
...
TCHAR szDir = _T("c:\\"); // or wherever.
HANDLE hFind = FindFirstFile(szDir, &ffd);
...
do {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// your code on 'ffd'
}
} while (FindNextFile(hFind, &ffd) != 0);
You can use Boost
Or, if you don't want Boost you can check out this thread where alternative options are discussed.
http://www.gamedev.net/community/forums/topic.asp?topic_id=523375
For best portability, use the boost filesystem library. Use opendir()/readdir() and friends for UNIX based systems.