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("\\\\?\\")
Related
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);
}
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.
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.