find file starting with a certain string [duplicate] - c++

This question already has answers here:
Fastest way to check if a file exists using standard C++/C++11,14,17/C?
(23 answers)
Closed 7 years ago.
I wonder how to check If a file exist or not :
For Example I have many files :
Boba.txt
James.txt
Jamy.txt
Boby.txt
How can I check if the file starting with Bob exists ?

Note, I'm assuming that you're on a Windows system and that the files are in the same directory.
You can use the FindFirstFile and FindNextFile functions to iterate through a directory. The prefix can be included in search term.
Example
std::string strSearch = "C:\\Some Directory\\Bob*";
WIN32_FIND_DATAA ffd;
HANDLE hFind = FindFirstFileA(strSearch .c_str(), &ffd);
do
{
std::string strFile = ffd.cFileName;
}
while (FindNextFileA(hFind, &ffd) != 0);
Proper error checking and how to deal with directories is left as an exercise for the reader.

Assuming you need to do this within C++, the boost::filesystem library can be very helpful. In that case, your problem can be solved by a variant of the solution posted here. In your case, you don't need a std::multimap, but can just use simple std::string::find.

You could open a file with fopen as read only "r". fopen will return a NULL pointer if the file does not exist. You can do this for any of the files needed by your program.
#include <cstdio>
int main ()
{
FILE **pFile;
pFile[0] = fopen ("Boba.txt","r");
pFile[1] = fopen ("Boby.txt","r");
if (pFile[0]!=NULL || pFile[1]!=NULL){
printf("File starting with \"bob\" exists.");
}
else printf("File does not exist.");
return 0;
}

Related

scan directory to find and open the file

I want to make a program that lets user enter drive name/folder(C:\ or f:\folder\) and a file name (test.exe) then program searches that file in the given drive or folder and opens the file.I managed to do the function that opens the file but cannot figure out how to search the file pass the location of file found to open it. Can anyone help me?
You can use boost::file_system. Here is documentation: http://www.boost.org/doc/libs/1_55_0/libs/filesystem/doc/index.htm
EDIT: after some time, I've got that my ansver were sligtly out of topic. To check if file exists you can use special boost::filesystem function.
bool exists(const path& p);
/EDIT
And directory iterator example: http://www.boost.org/doc/libs/1_55_0/libs/filesystem/doc/tutorial.html#Directory-iteration
It that example used std::copy, but you need filenames. So you can do something like this.
#include <boost/filesystem.hpp>
namespace bfs = boost::filesystem;
std::string dirPath = "."; // target directory path
boost::filesystem::directory_iterator itt(bfs::path(dirPath)); // iterator for dir entries
for ( ; itt != boost::filesystem::directory_iterator(); itt++)
{
const boost::filesystem::path & curP = itt->path();
if (boost::filesystem::is_regular_file(curP)) // check for not-a-directory-or-something-but-file
{
std::string filename = curP.string(); // here it is - filename in a directory
// do some stuff
}
}
If you are not expirienced with boost - building it can be complicated.
You can obtain prebuilded boost binaries for your compiller and platform at boost.teeks99.com
Also, if you cant use boost for some reason, there is platform specific ways of iterating a directory, but I dont know on which platform you are, so I cant provide you an example.
Try this:
char com[50]="ls ";
char path[50]="F:\\folder\\";
char file[50]="test.exe";
strcat(com,path);
strcat(com,file);
if (!system(com)) // system returns the return value of the command executed
cout<<"file not present\n";
else
{
cout<<"file is present\n";
strcat(path,file);
FILE* f = fopen(path,"r");
//do your file operations here
}

Analyzing a string for file name format [duplicate]

This question already has answers here:
How to check if string ends with .txt
(12 answers)
Closed 8 years ago.
A file name is being passed down into a function. The string needs to be checked to make sure it ends with ".bmp"
How do i check for that to later open the file?
For example: if a string contains "picture.txt" it will tell the user the string is not in the correct format. If a string contain "picture.bmp" it should accept it for later use of opening the file.
Thanks in advance!
What OS are you using? If it's Windows / Visual C++, you have functions that properly give you the extension given a file name (for example _spiitpath). If you want something portable, you have boost::filesystem to parse out the name.
The reason why you should use these functions instead of trying to cook something up yourself is that there could be corner or edge cases that you didn't consider, thus causing your code to give wrong results.
You can do something like this:
bool hasExtension(const string& filename, const string& extension)
{
size_t fnlen = filename.length();
size_t exlen = extension.length();
if (fnlen < exlen)
return false;
return memcmp(filename.c_str() + fnlen - exlen, extension.c_str(), exlen) == 0;
}
int main()
{
cout << hasExtension("file.txt", ".txt") << endl;
}

read only .txt files from directory which has subfolders too

I am trying to read only .txt files from directory.
I am not using arrays.
I am using opendir() to open my directory.
d->d_name lists all my files and also subfolders.
I want to read only .txt but not the subfolders.
please help me.
Thanks
Can you not use FindFirstFile and FindNextFile for this?
Well, something like:
call opendir() to open the directory
in a loop, call readdir to read each entry
for each entry, examine the name to see if the last 4 characters are ".txt"
if they are, do something
at the end, call closedir to close the directory
You can use the stat() function to determine the type of file your struct dirent represents.
struct stat sb;
int rc = stat(filename, &sb);
// error handling if stat failed
if (S_ISREG(sb.st_mode)) {
// it's a regular file, process it
} else {
// it's not a regular file, skip it
}
Read the man pages for details. Also take care that the filename in d_name does not contain the directory part. If you're in a different directory than what you opendir'd, you'll need to prepend the directory name (and a directory separator if required).
For a C++ alternative, please see boost::filesystem.
You could try put the filenames into a simple structure (string array or vector for example), then pass a reference to that structure to a function that prunes names that don't use the .txt extension
in the function, look at each filename (a for loop would be handy), and use the find function in the String library to see if the last four characters are == to .txt. You can reset the position of to start searching the string to string_name.length - 4 so that you're only comparing the last few characters.
Cplusplus.com is a great reference for things like the String library: http://www.cplusplus.com/reference/string/string/find/
Assuming you are on a Linux/Posix system, you can use scandir(...). You can find the details on the manual page, but in short, you have to provide a filter function that takes a dirent pointer as argument, and returns non-zero if the entry is to be included (in your case, you would check for the name ending in .txt, and possibly the file type in the dirent struct).
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
int main(int argc, char *argv[])
{
DIR *dir;
struct dirent *entry;
int pos;
if (argc < 2)
{
printf("Usage: %s <directory>\n", argv[0]);
return 1;
}
if ((dir = opendir(argv[1])) == NULL)
{
perror("opendir");
return 1;
}
while ((entry = readdir(dir)) != NULL)
{
if (entry->d_type != DT_REG)
continue;
pos = strlen(entry->d_name) - 4;
if (! strcmp(&entry->d_name[pos], ".txt"))
{
printf("%s\n", entry->d_name);
}
}
if (closedir(dir) == -1)
{
perror("closedir");
return 1;
}
return 0;
}

Read file names from a directory

I was wondering if there's an easy way in C++ to read a number of file names from a folder containing many files. They are all bitmaps if anyone is wondering.
I don't know much about Windows programming so I was hoping it can be done using simple C++ methods.
Boost provides a basic_directory_iterator which provides a C++ standard conforming input iterator which accesses the contents of a directory. If you can use Boost, then this is at least cross-platform code.
C++17 includes a standard way of achieve that
http://en.cppreference.com/w/cpp/filesystem/directory_iterator
#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
fs::create_directories("sandbox/a/b");
std::ofstream("sandbox/file1.txt");
std::ofstream("sandbox/file2.txt");
for(auto& p: fs::directory_iterator("sandbox"))
std::cout << p << '\n';
fs::remove_all("sandbox");
}
Possible output:
sandbox/a
sandbox/file1.txt
sandbox/file2.txt
Since you specify Windows,
I think you're looking for FindFirstFile() and FindNextFile().
Just had a quick look in my snippets directory. Found this. This uses Microsoft's Win32 API directly:
vector<CStdString> filenames;
CStdString directoryPath("C:\\foo\\bar\\baz\\*");
WIN32_FIND_DATA FindFileData;
HANDLE hFind = FindFirstFile(directoryPath, &FindFileData);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
if (FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY)
filenames.push_back(FindFileData.cFileName);
} while (FindNextFile(hFind, &FindFileData));
FindClose(hFind);
}
This gives you a vector with all filenames in a directory. It only works on Windows of course.
João Augusto noted in an answer:
Don't forget to check after FindClose(hFind) for:
DWORD dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
// Error happened
}
It's especially important if scanning on a network.
You could also use the POSIX opendir() and readdir() functions. See this manual page which also has some great example code.
Since you are programming for Windows I recommend you to use the native Win32 FindFirstFile() and FindNextFile() functions. These give you full control over how you search for files. These are simple C APIs and are not hard to use.
Another advantage is that Win32 errors are not hidden or made harder to get at due to the C/C++ library layer.
Another alternative is -
system("dir | findstr \".bmp\" > temp.txt ");
Now read temp.txt line by line to get all filenames.
Why not use glob()?
glob_t glob_result;
glob("/foo/bar/*",GLOB_TILDE,NULL,&glob_result);
for(unsigned int i=0;i<glob_result.gl_pathc;++i){
cout << glob_result.gl_pathv[i] << endl;
}

Example of using FindFirstFIleEx() with specific search criteria

I asked about finding in subdirs with criteria. First answer was use FindFirstFileEx(). It seems the function is no good for this purpose or I'm using it wrong.
So can someone explain how I would go about searching in a folder, and all it's subfolders for files that match (to give some sample criteria) .doc;.txt;*.wri; and are newer than 2009-01-01?
Please give a specific code example for those criteria so I know how to use it.
If it isn't possible, is there an alternative for doing this not-at-all-obscure task??? I am becoming quite baffled that so far there aren't well known/obvious tools/ways to do this.
From MSDN:
If you refer to the code fragment in that page:
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
void _tmain(int argc, TCHAR *argv[])
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
if( argc != 2 )
{
_tprintf(TEXT("Usage: %s [target_file]\n"), argv[0]);
return;
}
_tprintf (TEXT("Target file is %s\n"), argv[1]);
hFind = FindFirstFileEx(argv[1], FindExInfoStandard, &FindFileData,
FindExSearchNameMatch, NULL, 0);
if (hFind == INVALID_HANDLE_VALUE)
{
printf ("FindFirstFileEx failed (%d)\n", GetLastError());
return;
}
else
{
_tprintf (TEXT("The first file found is %s\n"),
FindFileData.cFileName);
FindClose(hFind);
}
}
You'll see that you can call FindFirstFileEx, where argv1 is a string (LPCSTR) pattern to look for, and &FindFileData is a data structure that contains file info of the found data.. hFind is the handle you use on subsequent calls with FindNextFile.. I think you can also add more search parameters by using the fourth and sixth parameter to FindFirstFileEx.
Good luck!
EDIT: BTW, I think you can check a file or dir's attributes by using GetFileAttributes() .. Just pass the filename found in FileFindData.. (filename can refer to a file's name or a directory name I think)
EDIT: MrVimes, here's what you could do (in pseudocode)
find the first file (match with *)
Check the file find data if it is ".", ".." (these are not really directories or files)
if check passed, check file find data if it has the attributes you are looking for (i.e. check filename, file attributes, even file creation time can be checked in the file find data, and what not) and do whatever with it
if check passed, do whatever you need to do with the file
if check failed, either call findnextfile or end, up to you
Something like that..
I think you use FindFirstFile to find all files and ignore the ones whose WIN32_FIND_DATA values don't match your search criteria.
Well you could use it to search for *.doc, *.txt and *.wri by passing those values as the name to search for:
FindFirstFileEx("*.doc", FindExInfoStandard, &fileData, FindExSearchNameMatch, NULL, 0);
To search by date is a little more complicated, but not overly so:
SYSTEMTIME createTime;
SYSTEMTIME searchDate;
FILETIME compareTime;
HANDLE searchHandle;
searchDate.wYear = 2009;
searchDate.wMonth= 1;
searchDate.wDay = 1;
SystemTimeToFileTime(searchDate, &compareTime);
searchHandle FindFirstFileEx("*", FindExInfoStandard, &fileData, FindExSearchNameMatch, NULL, 0);
if(searchHandle != INVALID_HANDLE_VALUE)
{
While(searchHandle != ERROR_NO_MORE_FILES)
{
FileTimeToSystemTime(fileData.ftCreationTime, &createTime);
if((ULARGE_INTEGER)compareTime < (ULARGE_INTEGER)createTime)
printf("%s matches date criteria", fileData.cFileName);
FindNextFile(searchHandle, &fileData);
}
}
You need to do two searches. The first is just to find the subdirs, and you do that without any file spec. The second search for the files uses the file spec.