3

I'm trying to code a program where it opens and reads a file automatically. But the problem is the file is stored in a folder which name is unknown. I only know where the folder is located and the file's name. How to get to that file's path in char* ?

Edit: example: d:\files\<random folder>\data.txt

I don't know the name of random folder but I know that it exists in d:\files

Galik
  • 47,303
  • 4
  • 80
  • 117
  • Do you know how to list all folders in d:\files? – dunkyp Jan 06 '16 at 15:54
  • 2
    What happens when two directories have the same file? – NathanOliver Jan 06 '16 at 15:56
  • 1
    There is currently no C++ way to iterate over files in a given directory (which is, of course, a shame and terrible legacy). You'd have to use third-party lib like boost. – SergeyA Jan 06 '16 at 15:56
  • Let's assume whomever made the files folder made sure that there was no file having the same names in different folders. – Redwanul Haque Sourave Jan 06 '16 at 16:04
  • @dunkyp No. I don't know. – Redwanul Haque Sourave Jan 06 '16 at 16:05
  • Try having a look at http://www.boost.org/doc/libs/1_59_0/libs/filesystem/doc/index.htm – dunkyp Jan 06 '16 at 16:06
  • 4
    I highly reccommed using `/` as your directory separator. The '\' is an escape character and some are control characters such as `\t`, `\f`, and `\b` (tab, formfeed and backspace). – Thomas Matthews Jan 06 '16 at 16:09
  • The random folder is the only folder in that directory – Redwanul Haque Sourave Jan 06 '16 at 16:16
  • you can probably use the solutions from here to solve your problem: http://stackoverflow.com/questions/67273/how-do-you-iterate-through-every-file-directory-recursively-in-standard-c – default Jan 06 '16 at 16:32
  • or from here http://stackoverflow.com/questions/4895317/how-can-i-automatically-open-the-first-file-in-a-folder-using-c?rq=1 – default Jan 06 '16 at 16:37
  • Some compilers (like GCC 5) have experimental support for the `` TS (Technical Specification): http://en.cppreference.com/w/cpp/experimental/fs – Galik Jan 06 '16 at 16:41
  • POSIX [provides a **f**ile **t**ree **w**alk function](http://pubs.opengroup.org/onlinepubs/009695399/functions/ftw.html): `ftw()`. You can use it to iterate over all entries in or under a specific directory, thus looking for your file. You may or may not have access to it via something like [Cygwin](https://www.cygwin.com/). – Andrew Henle Jan 06 '16 at 18:19
  • @ThomasMatthews: since this is Windows, I highly recommend *against* using forward slash as a directory separator. Windows accepts it in certain contexts, but not always. – Harry Johnston Jan 06 '16 at 23:39

3 Answers3

2

Since this is tagged windows, you might as well use the Windows API functions:

to enumerate and loop through all the files in a given directory.

To check for a directory, look at dwFileAttributes contained in the WIN32_FIND_DATA structure (filled by the calls to Find...File()). But make sure to skip . and .. directories. If needed, this can be done recursively.

You can check the links for some examples, or see Listing the Files in a Directory.

In case you are using MFC, you can use CFileFind (which is a wrapper around the API functions):

CFileFind finder;
BOOL bWorking = finder.FindFile(_T("*.*"));
while (bWorking)
{
   bWorking = finder.FindNextFile();
   TRACE(_T("%s\n"), (LPCTSTR)finder.GetFileName());
}
Danny_ds
  • 11,201
  • 1
  • 24
  • 46
2

Just for fun, I implemented this using the new, experimental <filesystem> FS Technical Specification supported by GCC 5.

#include <iostream>
#include <experimental/filesystem>

// for readability
namespace fs = std::experimental::filesystem;

int main(int, char* argv[])
{
    if(!argv[1])
    {
        std::cerr << "require 2 parameters, search directory and filename\n";
        return EXIT_FAILURE;
    }

    fs::path search_dir = argv[1];

    if(!fs::is_directory(search_dir))
    {
        std::cerr << "First parameter must be a directory: " << search_dir << '\n';
        return EXIT_FAILURE;
    }

    if(!argv[2])
    {
        std::cerr << "Expected filename to search for\n";
        return EXIT_FAILURE;
    }

    // file to search for
    fs::path file_name = argv[2];

    const fs::directory_iterator dir_end; // directory end sentinel

    // used to iterate through each subdirectory of search_dir
    fs::directory_iterator dir_iter(search_dir);

    for(; dir_iter != dir_end; ++dir_iter)
    {
        // skip non directories
        if(!fs::is_directory(dir_iter->path()))
            continue;

        // check directory for file

        // iterate through files in this subdirectory dir_iter->path()
        auto file_iter = fs::directory_iterator(dir_iter->path());

        for(; file_iter != dir_end; ++file_iter)
        {
            // ignore directories and wrong filenames
            if(fs::is_directory(file_iter->path())
            || file_iter->path().filename() != file_name)
                continue;

            // Ok we found it (the first one)
            std::cout << "path: " << file_iter->path().string() << '\n';
            return EXIT_SUCCESS;
        }
    }

    // Not found
    std::cout << file_name << " was not found in " << search_dir.string() << '\n';

    return EXIT_FAILURE;
}
Galik
  • 47,303
  • 4
  • 80
  • 117
-3

The idea is: list the directories under d:\files and try to open the file in each directory.

There isn't (yet) a standard C++ way of getting all the existing files/directories. A crude but easy way of doing this would be

system("dir d:\\files /b /ad > tmpfile");

This lists all directories (/ad), redirected to a temporary file. Then open the file:

std::ifstream list("tmpfile");

And read it:

std::string dirname;
std::string filename;
while (std::getline(list, dirname))
{
    filename = "d:\\files\\" + dirname + "\\data.txt";
    if ( ... file exists ... )
        break;
}

I call this method crude because it has problems that are hard/impossible to fix:

  • It overwrites a potentially useful file
  • It doesn't work if current directory is read-only
  • It will only work in Windows

It might be possible to use _popen and fgets instead of redirecting to file.

anatolyg
  • 26,506
  • 9
  • 60
  • 134