C++ Looping Through Files In Directory and Writing to a Different Directory

c++, io

Solution

Make sure you're passing the right `path` format to `FindFirstFile`.

From the documentation:

To examine a directory that is not a root directory, use the path to that directory, without a trailing backslash. For example, an argument of "C:\Windows" returns information about the directory "C:\Windows", not about a directory or file in "C:\Windows". To examine the files and directories in "C:\Windows", use an lpFileName of "C:\Windows\*".

Edit:

I'm not near a windows box right now (so this may not compile!) but I imagine that "loop over each file in a directory" would look something like this:

// argv[1] is the input path with no trailing characters, e.g. "c:\indir"

// add a wildcard because FindFirstFile expects e.g. "c:\indir\*"
TCHAR wildcard_path[MAX_PATH];
PathCombine(wildcard_path, argv[1], "*"); 

// iterate over each file
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile(wildcard_path, &ffd);
if (hFind == INVALID_HANDLE_VALUE) { } // error

do {
   // ignore directories
   if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {

      // create a full path for each file we find, e.g. "c:\indir\foo.txt"
      TCHAR file_path[MAX_PATH];
      PathCombine(file_path, argv[1], ffd.cFileName);

      // ...and do something with file_path.
   }
} while (FindNextFile(hFind, &ffd) != 0);

FindClose(hFind);

Problem

I am attempting to modify some existing C++ code to work with my needs, but having never used C++ before, I am having some difficulties. My goal is: ``` --> time and memory-intensive processes for preparation for each file in directory: open file; generate a tagged representation; //the current code just does this write file; //different directory but same filename ``` The reason I do not want to just call the C++ program for each file (with, for instance, a shell script) is that prior to the below code running, time and memory-intensive pre-processing steps are performed. (These take about 45-60sec. while the code only takes about 2-5sec. to run.) I have pasted the section of the code below. I want to read the arguments from the command line. ``` int main(int argc, char** argv) { /* pre-processing stuff */ /* for each file */ HANDLE hFind = INVALID_HANDLE_VALUE; string path = argv[1]; string outpath = argv[2]; WIN32_FIND_DATA ffd; //EDIT 2: cout << "Path: " << path << '\n'; cout << "Outpath: " << outpath << '\n'; hFind = FindFirstFile(path.c_str(), &ffd); if (hFind == INVALID_HANDLE_VALUE) { cout << "error searching directory\n"; return false; } do { //istream *is(&std::cin); string filePath = path + ffd.cFileName; ifstream in( filePath.c_str() ); if (in) { /* for each line */ string line; int n = 1; string str; string fullOutpath = outpath + ffd.cFileName; ofstream File; File.open(fullOutpath); while (getline(in, line)) { if (line.size() > 1024) { cerr << "warning: the sentence seems to be too long at line " << n; cerr << " (please note that the input should be one-sentence-per-line)." << endl; } string postagged = bidir_postag(line, vme, vme_chunking, dont_tokenize); /* output to file */ File << postagged << endl; //cout << postagged << endl; /* increment counter */ n++; } File.close(); } else { cout << "Problem opening file " << ffd.cFileName << "\n"; } } while (FindNextFile(hFind, &ffd) != 0); if (GetLastError() != ERROR_NO_MORE_FILES) { cout << "Something went wrong during searching\n"; } return true; } ``` Currently, I am getting a compiler error: EDIT: compiler error fixed, thanks Blood!, but see below... ``` error: no matching function for call to 'std::basic_ofstream<char>::open<std::string&> ``` Any thoughts? Please let me know if you need more code/information. Also, I should add that I'm running these on Windows XP using command prompt. Thanks. EDIT: It now compiles (thanks Blood), though when it runs it is only attempting to open the directory, not the files in the directory. ``` Problem opening file directory_name. ``` The ifstream should be opening the files in teh directory, not the directory itself. EDIT 2: I am running the executable fromt he command line with the following prompt: ``` .\tag.exe C:\indir C:\outdir ``` I have also tried: ``` .\tag.exe C:\indir\* C:\outdir\ ``` This enumerates all the files, but how can I capture them? Also, is there a simpler way to modify my code/input? I have also tried: ``` .\tag.exe C:\indir\ C:\outdir\ ``` This gives: error searching directory. EDIT 3: Using: ``` .\tag.exe "C:\indir\*" C:\outdir\ ``` I get the output: ``` Problem opening file . Problem opening file .. Problem opening file 2967 Problem opening file 2966 Problem opening file 4707 etc. (100s) ``` Solution: Here are the key changes to the code (thanks Nate Kohl!): ``` string path = argv[1]; path += "\\*"; hFind = FindFirstFile(path.c_str(),&ffd); // in the 'do-while' loop string filePath = argv[1]; filePath += "\\"; filePath += ffd.cFileName; ifstream in(filePath.c_str()); //regarding the outpath fullOutpath = outpath + "\\"; fullOutpath += ffd.cFileName; File.open(fullOutpath.c_str()); ``` and from the command line: ``` .\tag.exe C:\indir C:\outdir ``` The help was very much appreciated.

Original source

Related problems