how to find all folders under directory [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I tested find all folders under a directory with the environment of visual studio using mfc. Simply make a mfc dlg, add a button, paste the code below. The only variable to give is "product_path" directory with folders, empty folder is ok name like 123,or abc, or ABC.
Testing:
test 1 folders named 123,456.
result:can be found all.
test 2 folders named 123,456,ab.
result:the folder name ab can not found.
test 3 folders named 123,ab,AB.
result:the folder name AB can not found.
/*vector_folder_name used to store found folders*/
vector<CString> vector_folder_name;
/*product_path directory with folders*/
CString product_path=_T("..\\ProductType");
//sprintf(product_path,"..\\%s","ProductType");
if (product_path.Right(1) != "\\")
{
product_path += _T("\\");
}
product_path += _T("*.*");
CFileFind ff;
BOOL ret = ff.FindFile(product_path);
while (ret)
{
ret = ff.FindNextFile();
if (ret != 0)
{
if (ff.IsDirectory() && !ff.IsDots())
{
//CString path = ff.GetFilePath();
CString folder_name = ff.GetFileName();
vector_folder_name.push_back(folder_name);
//TraverseDir(path, vec);
}
//else /*if(!ff.IsDirectory() && !ff.IsDots())*/
//{
// CString name = ff.GetFileName();
// CString path = ff.GetFilePath();
// vector_folder_name.push_back(path);
//}
}
}
//sort(vector_folder_name.begin(),vector_folder_name.end());
sort(vector_folder_name.begin(),vector_folder_name.end(),compare1);
ff.Close(); // do not foget close

Your problem is totally unrelated to uppercase or lower case file names, and there is nothing magic about the situation, but your code is incorrect. It's also unrelated to the compare1 function
FindNextFile returns FALSE upon the last file found and therefore your code simply skips the last file found.
In other words if FindNextFile returns FALSE, it's not an error but it means that you've got the last file in the directory.
This (even simpler) code works:
...
BOOL ret = ff.FindFile(product_path);
while (ret)
{
ret = ff.FindNextFile();
if (ff.IsDirectory() && !ff.IsDots())
{
// it's a directory
CString folder_name = ff.GetFileName();
vector_folder_name.push_back(folder_name);
}
}
...
I've removed your outcommented code.

Related

Compare relationship of two folder

SCENARIO
PROCEDURE A gathers files from a webservice, and copies them to a root folder. Sometimes files are copied in a subfolder of the root, for example:
c:\root\file1
c:\root\file2
c:\root\filea
c:\root\<unique random name>\fileA
I suspect (but I'm not sure) that the webservice runs on linux-system and file names are case-sensitive. So, files are copied on a Windows file-system, and when uppercase/lowercase conflicts occure, files are copied in a subfolder. The subfolder has an unique randomly generated name.
PROCEDURE B scans files in the root and sub-folders in order to archive them. Files correctly archived are deleted. PROCEDURE A and PROCEDURE B don't run simultaneously.
And now my task ... I've to delete empty subfolder of the root.
FIRST SOLUTION (the easiest one)
When procedure B ends, I can scan empty subfolders of the root, end then delete them. Well ...
DWORD DeleteEmptySubFolder(LPCSTR szRootFolder)
{
DWORD dwError = 0;
CString sFolder(szRootFolder);
sFolder += "*.*";
CFileFind find_folder;
BOOL bWorking = find_folder.FindFile(sFolder);
while (bWorking)
{
bWorking = find_folder.FindNextFile();
if(find_folder.IsDots())
continue;
if(find_folder.IsDirectory())
{
if(PathIsDirectoryEmpty(find_folder.GetFilePath()))
if(!RemoveDirectory(find_folder.GetFilePath()))
dwError = GetLastError();
}
}
return dwError;
}
and now here are the problems: I haven't got any control on PROCEDURE B and I don't know when it ends. PROCEDURE B can call a user function after archiving each individual file.
SECOND SOLUTION (adequate but not too efficient)
I can still call the above function
DWORD DeleteEmptySubFolder(LPCSTR szRootFolder)
It's not efficient for sure, it will scan all subfolders of the root for each archived file, but it will delete only empty subfolders.
THIRD SOLUTION (it should work)
When procedure B call user function, I know the root folder and the full path of the archived file. So I can check if the folder of the file is a sub-folder of the root:
#define EQUAL_FOLDER 0
#define A_SUBFOLDER_OF_B 1
#define B_SUBFOLDER_OF_A 2
#define UNRELATED_FOLDER 3
int CompareFolderHiearachy(LPCSTR szFolderA, LPCSTR szFolderB)
{
if(_stricmp(szFolderA, szFolderB))
{
// StrStrI - Windows function (from shlwapi.dll) which finds the first occurrence of a substring within a string (the comparison is not case-sensitive).
if(StrStrI(szFolderA, szFolderB) == szFolderA)
return A_SUBFOLDER_OF_B;
else if(StrStrI(szFolderB, szFolderA) == szFolderB)
return B_SUBFOLDER_OF_A;
else
return UNRELATED_FOLDER;
}
else
return EQUAL_FOLDER;
}
Maybe this solution could work fine in my scenario, but it can only handle cases where folder/file names are consistent. For example:
local disk:
root: C:\folder\
filename: c:\folder\subfolder\fileA
mapped disk:
root: Z:\folder\
filename: Z:\folder\subfolder\fileA
UNC:
root: \\SERVER\folder\
filename: \\SERVER\folder\subfolder\fileA
and now my too generic and abstract question, can I check the hierarchy/realtionship of two folders in the worst scenario ?
\\server\folder1\folder2 (UNC)
z:\folder2 (network drive).
or even worst ....
\\MYPC\folder1\folder2
c:\folder2
Maybe I'm asking a bit perverse question ... but it's quite challenging and intriguing, isn't it ?
Thank you very much.
I improved the thrid solution; it can solve severale situations, but nfortunately it can't handle all the possible cases.
#define ERROR_OCCURED -1
#define EQUAL_FOLDER 0
#define A_SUBFOLDER_OF_B 1
#define B_SUBFOLDER_OF_A 2
#define UNRELATED_FOLDER 3
int CompareFolderHiearachy(LPCSTR szFolderA, LPCSTR szFolderB)
{
char pBuffer[32767];
DWORD dwBufferLength = 32767;
UNIVERSAL_NAME_INFO * unameinfo = reinterpret_cast< UNIVERSAL_NAME_INFO *>(pBuffer);
DWORD dwRetVal = WNetGetUniversalName(szFolderA, UNIVERSAL_NAME_INFO_LEVEL, reinterpret_cast<LPVOID>(pBuffer), &dwBufferLength);
if(dwRetVal != NO_ERROR && dwRetVal != ERROR_NOT_CONNECTED && dwRetVal != ERROR_BAD_DEVICE)
return ERROR_OCCURED;
CString sFolderA(unameinfo->lpUniversalName ? unameinfo->lpUniversalName : szFolderA);
ZeroMemory(pBuffer, dwBufferLength);
dwRetVal = WNetGetUniversalName(szFolderB, UNIVERSAL_NAME_INFO_LEVEL, reinterpret_cast<LPVOID>(pBuffer), &dwBufferLength);
if(dwRetVal != NO_ERROR && dwRetVal != ERROR_NOT_CONNECTED && dwRetVal != ERROR_BAD_DEVICE)
return ERROR_OCCURED;
CString sFolderB(unameinfo->lpUniversalName ? unameinfo->lpUniversalName : szFolderB);
if(_stricmp(sFolderA, sFolderB))
{
// StrStrI - Windows function (from shlwapi.dll) which finds the first occurrence of a substring within a string (the comparison is not case-sensitive).
if(StrStrI(sFolderA, sFolderB) == static_cast<LPCSTR>(sFolderA))
return A_SUBFOLDER_OF_B;
else if(StrStrI(szFolderB, sFolderA) == static_cast<LPCSTR>(sFolderB))
return B_SUBFOLDER_OF_A;
else
return UNRELATED_FOLDER;
}
else
return EQUAL_FOLDER;
}
It can't solve the following:
folder A: \\MY_PC\shared_folder\folderA
folder B: C:\shared_folder
(\\MY_PC\shared_folder and C:\shared_folder are the sane folder)
and:
folder A: \\SERVER\shared_folderA\shared_folderB
folder B: \\SERVER\shared_folderB

want it to be trim my TCHAR * from end only

TCHAR* pszBackupPath;
m_Edt_ExportPath.GetWindowText(pszBackupPath, dwcchBackupPath);
StrTrim(pszBackupPath, L" ");
StrTrim(pszBackupPath, L"\\"); //this line has issue
iRet = _tcslen(pszBackupPath);
boRet = PathIsNetworkPath(pszBackupPath);
if (FALSE == boRet)
{
// MessageBox with string "Entered path is network path.
}
boRet = PathIsDirectory(pszBackupPath);
if (FALSE == boRet)
{
// MessageBox with string "Entered path is not a valid directory.
}
This is a part of my code in MFC.
I am passing a network path from UI. But because of StrTrim(pszBackupPath, L"\\") "\\" get trimmed from start and end. But I want it to be trimmed from end only.
I don't know any direct API. Please suggest.
There is a simple function to do that: PathRemoveBackslash (or PathCchRemoveBackslash for Windows 8 and later).

How to get current directory of a specific drive in Visual Studio Express 2013(C++)?

I am porting a program from Borland C++ Builder to Visual Studio 2013 (C++). The program uses getcurdir to get the current directory of a drive. This function has a parameter drive, but the Microsoft equivalent function getcwd don't have such parameter. How can I do it?
As you tagged visual studio, I assume you'r using windows. Beside that current directory is just one, (i.e. where the executable is located or other if you've moved to) current directory won't be different depending on current drive, I think. Then, in windows you may use the function GetCurrentDirectory from winapi. The prototype is:
DWORD WINAPI GetCurrentDirectory(
_In_ DWORD nBufferLength,
_Out_ LPTSTR lpBuffer
);
You may get details here.
Example:
TCHAR cwd[100];
GetCurrentDirectory(100,cwd);
// now cwd will contain absolute path to current directory
(Yes I know this is an old entry, just for the records if somebody stumbles over the same issue...)
As deeiip already said correctly, in Windows there is only 1 current directory, but cmd.exe fakes DOS behavior when there was 1 current directory per drive.
If you need to access cmd's current directory per drive, use the according hidden environment variables, e.g. "%=C:%".
Here an example application (in C#):
using System;
static class Module1 {
public static void Main(String[] args) {
var myFolder = GetCurrentFolderPerDrive(args[0]); //e.g. "C:"
Console.WriteLine(myFolder);
}
private static string GetCurrentFolderPerDrive(string driveLetter) {
driveLetter = NormalizeDriveLetter(driveLetter);
string myEnvironmentVariable = $"%={driveLetter}%";
string myResult = Environment.ExpandEnvironmentVariables(myEnvironmentVariable);
if (myResult == myEnvironmentVariable) return $"{driveLetter.ToUpperInvariant()}\\"; //No current folder set, return root
return myResult;
}
private static String NormalizeDriveLetter(String driveLetter) {
if (String.IsNullOrWhiteSpace(driveLetter)) throw new ArgumentNullException(nameof(driveLetter), "The drive letter is null, empty or white-space.");
Boolean throwException = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".IndexOf(driveLetter[0]) < 0);
if (!throwException) {
if (driveLetter.Length == 1) {
driveLetter += ':';
} else if (driveLetter.Length != 2) {
throwException = true;
}
}
if (throwException) throw new ArgumentException($"A well-formed drive letter expected, e.g. \"C:\"!\r\nGiven value: \"{driveLetter}\".", nameof(driveLetter));
return driveLetter;
}
}

C++ iterating through files and directories

I'm working on a C++ program that will automatically backup my work to my FTP server. So far I am able to upload a single file, by specifying a file name using this
CString strFilePath = szFile ;
int iPos = strFilePath.ReverseFind('\\');
CString strFileName = strFilePath.Right((strFilePath.GetLength()- iPos-1) );
CString strDirPath = m_szFolderDroppedIn ;
strDirPath = strDirPath.Mid(0,strDirPath.GetLength() - 1);
int iPost = strDirPath.ReverseFind('\\');
CString strDirName = strDirPath.Right((strDirPath.GetLength()- iPost -1) );
bool curdir = ftpclient.SetServerDirectory((char*)strDirName.GetBuffer(strDirName.GetLength()));
//Upload to Server
int uploadret = ftpclient.PutFile(szFile,(char*)strFileName.GetBuffer(strFileName.GetLength()),0,true,dwLastError);
m_lsDroppedFiles.RemoveAll();
break;
}
Now I want to be able to iterate through a directory (Which contains subdirectories) and recursively call. I'm having a problem getting a hold of the files in the directory.
Any help or code snippet...
Since you are using MFC, you can use the CFileFind class. Example code is given in MSDN. Alternatively, you can use boost.filesystem for the same.
#Swapnil: If you use boost::filesystem, there is a recursive_directory_iterator

Populating a database with file names from directories

I have an application which behaves as a slideshow for all pictures in a folder. It is written in Borland's C++ Builder (9). It currently uses some borrowed code to throw the filenames into a listbox and save the listbox items as a text file.
I want to update this so that the filenames are stored in a proper database so that I can include extra fields and do proper SQL things with it.
So basically I would be able to work it out if I saw some 'sample' code doing the same thing.
So if anyone knows of any code that does this I would be greatful. It needs to be able to do it on certain file types... not just all the files.
You basically neeed to write a recursive function with a TDataSet parameter.
(I could not compile my code, so you get it "as is")
void AddFiles(AnsiString path, TDataSet *DataSet)
{
TSearchRec sr;
int f;
f = FindFirst(path+"\\*.*", faAnyFile, sr);
while( !f )
{
if(sr.Attr & faDirectory)
{
if(sr.Name != "." && sr.Name != "..")
{
path.sprintf("%s%s%s", path, "\\", sr.Name);
AddFiles(path, DataSet);
}
}
else
{
DataSet->Append();
DataSet->FieldByName("Name")->Value = sr.Name;
/* other fields ... */
DataSet->Post();
}
f = FindNext(sr);
}
FindClose(sr);
}