Reputation: 1471
I'm using the opendir and readdir functions to search for file names containing .txt in the given directory.
Is there any way I can test a certain extension
via a function without using a loop? (currently I have to loop through de-> d_filename
to check but they are quite complicated, in addition I tried de->d_type
however it did not return the extension)
In addition, this function is returning the name of the file name, my desired result is to get the path name from the beginning, is there a function return wchar_t* similar to de->d_fullfilepath?
This is all I have :
DIR* dr = opendir(lpszFolder);
vector<const wchar_t*> names; //get list file with extension .txt then push to this vector
if (dr == NULL) // opendir returns NULL if couldn't open directory
{
printf("Could not open current directory");
return {};
}
// Refer http://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
// for readdir()
while ((de = readdir(dr)) != NULL)
{
if (de->d_type ... 'txt') // function get just .txt file.
{
wchar_t* pwc =new wchar_t(lpszFolder); //initialize new instance file path
const size_t cSize = de->d_namlen + 1; //get file len
mbstowcs(pwc, de->d_name, cSize); //combine thisfilepath + extension
names.push_back(pwc);
}
}
Upvotes: 1
Views: 390
Reputation: 11219
You might consider strrchr
Locate last occurrence of character in string Returns a pointer to the last occurrence of character in the C string str.
The terminating null-character is considered part of the C string. Therefore, it can also be located to retrieve a pointer to the end of a string.
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <string>
#include <vector>
using namespace std;
const char *get_filename_ext(const char *filename) {
const char *dot = strrchr(filename, '.');
return (!dot || dot == filename) ? "" : dot + 1;
}
int main(int ac, char **av) {
if (ac != 2)
return 1;
const char *lookup = (ac==3) ? av[2] : "txt";
const char *lpszFolder = av[1];
DIR* dr = opendir(lpszFolder);
vector<const wchar_t*> names; //get list file with extension .txt then push to this vector
if (dr == NULL) // opendir returns NULL if couldn't open directory
{
printf("Could not open current directory");
return (1);
}
struct dirent *ent;
uint32_t len = sizeof(((dirent*)0)->d_name);
char ext[len];
while ((ent = readdir (dr)) != NULL) {
(void)ext;
strncpy(ext, get_filename_ext(ent->d_name), len-1);
if (!strcmp(lookup, ext))
names.push_back(reinterpret_cast < wchar_t*>(ent->d_name));
}
closedir(dr);
for (auto name : names)
printf("%s", (char *)name);
return 0;
}
Test with:
g++ a.cpp && ./a.out myfolder
will look for all files with ".txt" extensions
Or if you want a specific extension like ☠ :
g++ a.cpp && ./a.out myfolder ☠
Upvotes: 3
Reputation: 15277
In modern C++ you should use algorithms from the std::algorithm library to avoid loops. These algorithms prevent many possible problems from the wrong usage of loops, mostly out of bounds problems.
And, C++ can deal with "wide strings" with the base data type wchar_t. You can simply use std::wstring
instead of std::string
.
Any you should not and never use plain C-Style arrays or pointers to char or wchar_t. These are that error prone that they should really not be used.
Even if you have legacy code with "old" "char*"-strings, put them into a std::string
and use those in the future.
Next: You MUST NOT use raw pointers for owned memory. You should try to avoid pointers in general and use smart pointers instead. And you should not use new
in C++. There is nearly no need for it any longer. Use containers from the STL.
Now back to your original question:
How to check char array contain any char without loop in C++?
Yes, by using std::algorithms
and iterators
Is there any way I can test a certain extension via a function without using a loop?
Yes, ths std::filesystem will help you. It has all the functionality you need and is superior to all handcraftedt solutions. It can especially also deal with wchar_t
and wide stringsstd::wstring
In the following code, I generated an example function that returns a std::vector
filled with all fule file paths in a specified directory with a given string.
#include <iostream>
#include <string>
#include <filesystem>
#include <vector>
#include <algorithm>
// Name space alias for saving typing work
namespace fs = std::filesystem;
// A function, that gets a path to a director as wstring and returns all file paths as wstring with a given extension
std::vector<std::wstring> getFilesWithCertainExtension(const std::wstring& dirPath, const std::wstring& extension = L".txt") {
// Put the wstring with path to the the directory in a generic path variable
fs::path startPath{ dirPath };
// Here we sill store all directory entries having a given extension
std::vector<fs::directory_entry> filesInDirectory{};
// Go thorugh the directory and copy all directory entries with a given extension int our vector
std::copy_if(fs::directory_iterator(startPath), {}, std::back_inserter(filesInDirectory),
[&](const fs::directory_entry& de) { return de.path().extension().wstring() == extension; });
// The result of this function should be a vector of wstrings
std::vector<std::wstring> result(filesInDirectory.size());
// Convert directory entries to wstrings
std::transform(filesInDirectory.begin(), filesInDirectory.end(), result.begin(),
[](const fs::directory_entry& de) { return de.path().wstring(); });
return result;
}
int main() {
// Read all files from c:\\temp with the default extension ".txt"
std::vector<std::wstring> files = getFilesWithCertainExtension(L"c:\\temp");
// Show full paths to user
for (const std::wstring& ws : files) std::wcout << ws << L"\n";
return 0;
}
This is one of many possible solutions. This could even be optimized, if I would understand your requirements better.
I would explain the function in more detail. But, becuase anyway nobody will read this, I save the time.
Upvotes: 3