How move n-first files to another directory using C++ (VS) - c++

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.

Related

Using built in Windows Methods to get Contents of Folder

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);
}

Error in iterative directory listing using C++

I've come across this code for directory listing on Windows using C++,and I've understood that you can search a directory with these APIs: FindFirstFileEx, FindNextFile and CloseFind. You'll need to #include , that'll get you access to the Windows API.
I'm not able to understand how this code works, as a result not able to make out the compilation error.
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strcat.h>
#pragma comment(lib, "User32.lib")
void DisplayErrorBox(LPTSTR lpszFunction);
int _tmain(int argc, TCHAR *argv[])
{
WIN32_FIND_DATA ffd;
LARGE_INTEGER filesize;
TCHAR szDir[MAX_PATH];
size_t length_of_arg;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError=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("\\*"));
// 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
{
filesize.LowPart = ffd.nFileSizeLow;
filesize.HighPart = ffd.nFileSizeHigh;
_tprintf(TEXT(" %s %ld bytes\n"), ffd.cFileName, filesize.QuadPart);
}
}
while (FindNextFile(hFind, &ffd) != 0);
dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
DisplayErrorBox(TEXT("FindFirstFile"));
}
FindClose(hFind);
return dwError;
}
void DisplayErrorBox(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the error message and clean up
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}
Gives out the followoing error on codeblocks:
fatal error: strcat.h: No such file or directory
#include <strcat.h>
^
compilation terminated.
strcat is defined in string.h not strcat.h
Then, you do not seem to be using strcat, maybe you can remove that.

windows.h How to use FindFirstFile() and FindNextFile() to list all files in a directory?

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!

CopyFile error code 2

I have to create console application, which finds all .txt files in directory and makes copies of them to .copytxt format in the same directory. Program returns me error code 2 from CopyFile function. I really dont know where is the problem. I tried to use this reference: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365522(v=vs.85).aspx
Here is my code:
#include "stdafx.h"
#include "windows.h"
#define SOURCE_PATH _T(R"(C:\Users\XXXXX\Documents\4.semester\PB173\Ukol1\text\)")
int _tmain(int argc, _TCHAR* argv[])
{
WIN32_FIND_DATA findData;
HANDLE findHandle;
BOOL fFinished = FALSE;
TCHAR oldPath[MAX_PATH];
TCHAR newPath[MAX_PATH];
DWORD attrs;
_tcscpy_s(oldPath, _T("\\?\)"));
_tcscpy_s(oldPath, SOURCE_PATH);
_tcscat_s(oldPath, _T("*.txt"));
_tprintf(_T("%s\n"), oldPath);
findHandle = FindFirstFile(oldPath, &findData);
if (findHandle != INVALID_HANDLE_VALUE)
{
_tprintf(_T("The first file found is %s\n"), findData.cFileName);
while (!fFinished)
{
_tcscpy_s(newPath, _T("\\?\)"));
_tcscpy_s(newPath, SOURCE_PATH);
TCHAR* pChar;
TCHAR* savePtr;
pChar = _tcstok_s(findData.cFileName, _T("."), &savePtr);
_tcscat_s(newPath, pChar);
_tcscat_s(newPath, _T(".copytxt"));
_tprintf(_T("%s\n"), newPath);
//StringCchPrintf(newPath, sizeof(newPath) / sizeof(newPath[0]), TEXT("%s\\%s"), oldPath, findData.cFileName);
if (CopyFile(findData.cFileName, newPath, FALSE))
{
attrs = GetFileAttributes(findData.cFileName);
if (attrs == INVALID_FILE_ATTRIBUTES) break;
SetFileAttributes(newPath, attrs);
_tprintf(_T("File %s copied successfully.\n"), findData.cFileName);
}
else
{
_tprintf(_T("Could not copy file %s.\n"), findData.cFileName);
_tprintf(_T("%d\n"), GetLastError());
break;
}
if (!FindNextFile(findHandle, &findData))
{
if (GetLastError() == ERROR_NO_MORE_FILES)
{
_tprintf(_T("All files *.txt were copied.\n"));
fFinished = TRUE;
}
else
{
_tprintf(_T("Could not find next file.\n"));
break;
}
}
}
FindClose(findHandle);
}
else
{
_tprintf(TEXT("FindFirstFile failed (%d)\n"), GetLastError());
}
return 0;
}
You need to strcat the cFileName to the end of the the source path before attempting the copyfile, else the file will not be found.
From MSDN:
The cFileName field in this structure will not include a path, even if
a path was used in the call to FindFirstFile/FindNextFile. So if you
call FindFirstFile("C:\Windows\System32*", &finddata), finddata may
contain e.g. "drivers" or "cmd.exe" but not
"C:\Windows\System32\drivers" or "C:\Windows\System32\cmd.exe".
You need to escape \ as \\ when you want to use an actual \ character in literals.
You are also putting parenthesis characters inside your literal values. You need to remove them.
Change
#define SOURCE_PATH _T(R"(C:\Users\XXXXX\Documents\4.semester\PB173\Ukol1\text\)")
To
#define SOURCE_PATH _T("C:\\Users\\XXXXX\\Documents\\4.semester\\PB173\\Ukol1\\text\\")
And
_T("\\?\)")
To
_T("\\\\?\\")

How can i Get a list of all files in the computer with registry file and memory files in the c programming language

I am trying to get all the files in all of the computer and even the registry files using the c programming language or c++
i Have this code put it doesn't five me list of registry files and subfiles
#include <dirent.h>
#include <stdio.h>
int main(void)
{
system("Title G:\\");
DIR *d;
struct dirent *dir;
d = opendir("D:\\");
if (d)
{
while ((dir = readdir(d)) != NULL)
printf("%s\n", dir->d_name);
closedir(d);
}
getch();
}
You can use FindFirstFile, FindNextFile, and FindClose to list files in a specified directory.
What do you mean with the registry files? Do you mean registration database entries that has filenames specified as strings?
Here is an example from MSDN.
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#pragma comment(lib, "User32.lib")
void DisplayErrorBox(LPTSTR lpszFunction);
int _tmain(int argc, TCHAR *argv[])
{
WIN32_FIND_DATA ffd;
LARGE_INTEGER filesize;
TCHAR szDir[MAX_PATH];
size_t length_of_arg;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError=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("\\*"));
// 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
{
filesize.LowPart = ffd.nFileSizeLow;
filesize.HighPart = ffd.nFileSizeHigh;
_tprintf(TEXT(" %s %ld bytes\n"), ffd.cFileName, filesize.QuadPart);
}
}
while (FindNextFile(hFind, &ffd) != 0);
dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
DisplayErrorBox(TEXT("FindFirstFile"));
}
FindClose(hFind);
return dwError;
}
void DisplayErrorBox(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the error message and clean up
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}
You can use Change Journals
(very complex) for this !
See MSDN docs.