Read files, with recursive search

I made a program within an api framework that searches a known folder for .m3u files, it then reads the m3u line by line and if it finds a string that the user enters it makes a copy of that m3u into another folder [which it makes itself).

Working ok but I would like to change it to perform the task recursively
Any links or hints would be great thanks.

I'm still a novice, but I'll try to keep up.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

	char homeF[512], getFilePath[512], getFileName[512], getFileTitle[512];
	GetStringInfo("get_vdj_folder", &homeF[0], 512);
	GetStringInfo("get_browsed_filepath", &getFilePath[0], 512);
	GetStringInfo("get_browsed_artist", &getFileName[0], 512);
	GetStringInfo("get_browsed_title", &getFileTitle[0], 512);
	std::stringstream allPLs, makeSRFolder, makeATFolder;
	// this is the root playlistfolder
	allPLs << homeF << "\\playlists\\*.m3u";
	makeSRFolder << homeF << "\\playlists\\search results\\";
	makeATFolder << homeF << "\\playlists\\search results\\" << getFileName << "\\";
	makeTTFolder << homeF << "\\playlists\\search results\\" << getFileName << "\\" << getFileTitle;
	CreateDirectoryA(makeSRFolder.str().c_str(), NULL);
	CreateDirectoryA(makeATFolder.str().c_str(), NULL);
	CreateDirectoryA(makeTTFolder.str().c_str(), NULL);
	_finddata_t data;
	intptr_t ff = _findfirst(allPLs.str().c_str(), &data);
	if (ff != -1)
	{
		int res = 0;
		while (res != -1)
		{
			std::stringstream plName;
			plName << homeF << "\\playlists\\" << data.name;
			string line;
			ifstream myfile(plName.str().c_str());
			if (myfile.is_open())
			{
				while (getline(myfile, line))
				{

					if (line == getFilePath)
					{
						std::stringstream nplName;

						nplName << homeF << "\\playlists\\search results\\" << getFileName << "\\" << getFileTitle << "\\" << data.name;
						CopyFileA(plName.str().c_str(), nplName.str().c_str(), 0);
						itWorked = 1;
						myfile.close();
					}
				}
			}
			res = _findnext(ff, &data);
		}
	_findclose(ff);
	}
Last edited on
Take a look at std::filesystem. It has a very nice directory iterator, which you can use to write a recursive directory search.
Thanks for the hint, although I'm struggling to understand how to apply that to my project.
I can sometimes understand examples but often struggle how to apply in the real world
Something like this, perhaps:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <filesystem>
#include <vector>
#include <string>

// return a list of files with the specified extension 
std::vector<std::string> file_name_list( const std::string& path_to_dir, const std::string& extension = ".m3u" )
{
    namespace fs = std::filesystem ;

    if( fs::is_directory(path_to_dir) )
    {
        std::vector<std::string> file_names ;

        for( const auto& entry : fs::recursive_directory_iterator(path_to_dir) )
        {
            // note: in native windows file systems, make the comparison for extension case-insensitive
            if( entry.is_regular_file() && entry.path().extension() == extension )
                file_names.push_back( entry.path().string() ) ;
        }

        return file_names ;
    }

    else return {} ; // not a directory; return an empty vector
}
Thank you so much, so I'm not confusing myself even more, the above is a function,
And I call it like this

1
2
3
4
std::stringstream allPLs1;
allPLs1 << homeF << "\\playlists\\";
const char* cstr1 = str.c_str();
file_name_list(cstr1);


As I step thru the program I see it make the vector, and it recursively includes all .m3u files, cool.

Now I'm lost again
do I add my read line by line code into this function [not sure how]
or do I work with the return file_names , again not sure how as I haven't returned it to anything [and not sure how]
Sorry to be a PIA with this, I am trying to learn.
Something like this, perhaps (caveat:untested):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <filesystem>
#include <vector>
#include <string>
#include <fstream>

// return a list of files with the specified extension 
std::vector<std::string> file_name_list( const std::string& path_to_dir, const std::string& extension = ".m3u" )
{
    namespace fs = std::filesystem ;
    using iterator =  fs::recursive_directory_iterator ;
    
    if( fs::is_directory(path_to_dir) )
    {
        std::vector<std::string> file_names ;

        for( const auto& entry : fs::recursive_directory_iterator(path_to_dir) )
        {
            // note: in native windows filesystems, make the comparison for extension case-insensitive
            if( entry.is_regular_file() && entry.path().extension() == extension )
                file_names.push_back( entry.path().string() ) ;
        }

        return file_names ;
    }

    else return {} ;
}

// return true if the file contains the searched_for_line
bool contains_line( const std::string& file_name, const std::string& searched_for_line )
{
    if( std::ifstream file { file_name } )
    {
        std::string line ;
        while( std::getline( file, line ) ) if( line == searched_for_line ) return true ;
    }

    return false ; 
}

// return true if the file was copied to the destination directory
bool copy_to_dir( const std::filesystem::path& srce_file, const std::filesystem::path& dest_directory )
{
    // compose the path to the destination file 
    const auto dest_path = dest_directory / srce_file.filename() ;
    return std::filesystem::copy_file( srce_file, dest_path,
                                       std::filesystem::copy_options::update_existing ) ;
}

int main()
{
    const std::string extension = ".m3u" ;
    const std::string srce_dir = "place the full path to the source directory here" ;
    const std::string dest_dir = "place the full path to the destnation directory here" ;
    const std::string line_to_search_for = "place the text of the line to search for here" ;

    // for each file name in the returned file name list
    for( const std::string& fname : file_name_list( srce_dir, extension ) )
    {
        // if the file contains the line of interest
        if( contains_line( fname, line_to_search_for ) )
        {
            // copy the file to the destination directory
            const auto srce_path = srce_dir / std::filesystem::path(fname).filename() ;
            const bool copied = copy_to_dir( srce_path, dest_dir ) ;
            if( !copied ) { /* copy failed (file was not copied); handle the error if required */ }
        }
    }
}
Thank you thank you thank you, I'd have never of got there, great commenting too. [idiot friendly :) ]
one problem line when dealing with a sub folder
line 46
gives the location of the file to copy as the parent folder and not the subfolder, I followed it back to line 65 and I poked at it until I got this and it worked!

auto srce_path = fname;
I honestly don't know if I just got lucky or I've done something unbelievably stupid.
But thanks again to all
Topic archived. No new replies allowed.